详解C#泛型(三)
一、前面两篇文章分别介绍了定义泛型类型、泛型委托、泛型接口以及声明泛型方法:
首先回顾下如何构建泛型类:
public class MyClass<T>
{
public void MyFunc()
{
//…
}
}
其中,尖括号<>中的T代表的是该泛型类的类型参数,在使用时可以指定其类型,例如,指定类型参数为整数类型,创建封闭式构造类MyClass<int>:
MyClass<int> myObj = new MyClass<int>();
二、这一篇我们了解一下泛型的作用机制,泛型是运行时起作用的一套机制,根据运行时类型参数被指定为值类型还是引用类型其使用方式有所不同:
1.当类型参数被指定为值类型时,会在第一次指定该特定值类型的类型时创建该类型唯一的专用化泛型类型,泛型类型中的类型参数会被替换为相应的值类型;
※此时,运行时会创建不同封闭式构造类型的类型信息对象,它们的类型句柄指向不同的类型信息对象,不同封闭式构造类型的方法句柄也指向不同的方法信息对象;
2.当类型参数被指定为引用类型时,会在第一次指定任意引用类型时创建一个通用化泛型类型,泛型类型中的类型参数会被替换为该引用类型,并在之后每次指定为引用类型时重用该泛型类型并修改其中类型参数的类型;造成这种差异的原因可能在于所有的引用大小相同;
※此时,运行时依然会创建不同封闭式构造类型的类型信息对象,它们的类型句柄也指向不同的类型信息对象,但是它们共用一套方法句柄,即不同封闭式构造类型的方法句柄指向同一个方法信息对象;
3.对于给定的泛型类:
public class MyClass<T>
{
public void MyFunc()
{
//…
}
}
获取不同封闭式构造类型的类型句柄和方法句柄:
Type type1 = typeof(MyClass<int>);
Type type2 = typeof(MyClass<long>);
Type type3 = typeof(MyClass<string>);
Type type4 = typeof(MyClass<Array>);
//以下类型句柄各不相同
Console.WriteLine(type1.TypeHandle.Value);
Console.WriteLine(type2.TypeHandle.Value);
Console.WriteLine(type3.TypeHandle.Value);
Console.WriteLine(type4.TypeHandle.Value);
//最后两个方法句柄相同,其它方法句柄各不相同
Console.WriteLine(type1.GetMethod("MyFunc").MethodHandle.Value);
Console.WriteLine(type2.GetMethod("MyFunc").MethodHandle.Value);
Console.WriteLine(type3.GetMethod("MyFunc").MethodHandle.Value);
Console.WriteLine(type4.GetMethod("MyFunc").MethodHandle.Value);
※在访问任何泛型类型之前,CLR会先创建MyClass<>的类型信息对象;
打印结果:

可以发现,最后两个泛型类型的MyFunc方法的方法句柄指向相同;但是不同类型参数的情况下,还是会创建对应的泛型类型对象,这使得泛型单例成为可能:
三、对于封闭式构造类型,只要其类型参数不完全相同,CLR就会在初次访问该类型之前创建该类型的类型信息对象并调用其对应唯一的静态构造函数,例如对于有静态构造函数的泛型类MyClass<T>,在初次访问MyClass<int>、MyClass<string>等封闭式构造类之前都会调用一次其对应唯一的静态构造函数,这也是创建泛型单例的基础:
public class MyClass<T>
{
static MyClass()
{
Console.WriteLine(typeof(T).FullName);
}
}
MyClass<int> obj1 = new MyClass<int>();
MyClass<long> obj2 = new MyClass<long>();
MyClass<Array> obj4 = new MyClass<Array>();
打印结果:

四、运行时动态构建泛型:
Type myType = typeof(MyClass<>); //获取未指定任何类型参数的开放式构造类的类型信息,多个类型参数时添加,:typeof(MyClass<,>)
myType = myType.MakeGenericType(typeof(int)); //通过类型信息的实例方法MakeGenericType()构建指定所有类型参数的封闭式构造类的类型信息,如未指定所有类型参数会抛出异常ArgumentException
//也可以直接获取封闭式构造类的类型信息,当类型参数在一开始就确定时推荐使用此种方式
//myType = typeof(MyClass<int>); //多个类型参数时需要同时指定:typeof(MyClass<int, string>)
注意:通过反射只可以获取未指定任何类型参数的开放式构造类MyClass<,>的类型信息和指定所有类型参数的封闭式构造类MyClass<int, string>的类型信息,即无法获取MyClass<int, >的类型信息;
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的认可是我写作的最大动力!
作者:Minotauros
出处:https://www.cnblogs.com/minotauros/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
详解C#泛型(三)的更多相关文章
- 详解C#泛型(二) 获取C#中方法的执行时间及其代码注入 详解C#泛型(一) 详解C#委托和事件(二) 详解C#特性和反射(四) 记一次.net core调用SOAP接口遇到的问题 C# WebRequest.Create 锚点“#”字符问题 根据内容来产生一个二维码
详解C#泛型(二) 一.自定义泛型方法(Generic Method),将类型参数用作参数列表或返回值的类型: void MyFunc<T>() //声明具有一个类型参数的泛型方法 { ...
- JDBC详解系列(三)之建立连接(DriverManager.getConnection)
在JDBC详解系列(一)之流程中,我将数据库的连接分解成了六个步骤. JDBC流程: 第一步:加载Driver类,注册数据库驱动: 第二步:通过DriverManager,使用url,用户名和密码 ...
- 详解TCP的三次握手四次断开
本文将分别讲解经典的TCP协议建立连接(所谓的“3次握手”)和断开连接(所谓的“4次挥手”)的过程. 尽管TCP和UDP都使用相同的网络层(IP),TCP却向应用层提供与UDP完全不同的服务.TCP提 ...
- 第6章 传输层(详解TCP的三次握手与四次挥手)
第6章 传输层 传输层简介 传输层为网络应用程序提供了一个接口,并且能够对网络传输提供了可选的错误检测.流量控制和验证功能.TCP/IP传输层包含很多有用的协议,能够提供数据在网络传输所需的必要寻址信 ...
- CocoaPods详解之(三)----制作篇
CocoaPods详解之----制作篇 作者:wangzz 原文地址:http://blog.csdn.net/wzzvictory/article/details/20067595 转载请注明出处 ...
- [转]iOS学习之UINavigationController详解与使用(三)ToolBar
转载地址:http://blog.csdn.net/totogo2010/article/details/7682641 iOS学习之UINavigationController详解与使用(二)页面切 ...
- iOS学习之UINavigationController详解与使用(三)ToolBar
1.显示Toolbar 在RootViewController.m的- (void)viewDidLoad方法中添加代码,这样Toobar就显示出来了. [cpp] view plaincopy [ ...
- 详解C#泛型(二)
一.自定义泛型方法(Generic Method),将类型参数用作参数列表或返回值的类型: void MyFunc<T>() //声明具有一个类型参数的泛型方法 { Type generi ...
- Linux常用命令详解(第三章)(ping、kill、seq、du、df、free、date、tar)
本章命令(共7个): 1 2 3 4 5 6 7 8 ping kill seq du df free date tar 1." ping " 作用:向网络主机发送ICMP(检测主 ...
随机推荐
- Docker Compose部署 nginx代理Tomcat集群
一.简介 使用Docker镜像部署Nginx代理的多个Tomcat集群: 使用Dockerfile构建nginx镜像 使用Dockerfile构建tomcat镜像 mysql镜像使用docker hu ...
- Forward团队-爬虫豆瓣top250项目-设计文档
组长地址:http://www.cnblogs.com/mazhuangmz/p/7603594.html 成员:马壮,李志宇,刘子轩,年光宇,邢云淇,张良 设计方案: 1.能分析HTML语言: 2. ...
- _ZSkill_快捷键_Xcode快捷键
Xcode 快捷键使用 Command 用来导航,控制导航区域 Alt 控制右边的部分. 如Assistant Editor ,utility editor. Control 编辑区域上的jump b ...
- Codeforces Round #540 (Div. 3)--1118D1 - Coffee and Coursework (Easy version)
https://codeforces.com/contest/1118/problem/D1 能做完的天数最大不超过n,因为假如每天一杯咖啡,每杯咖啡容量大于1 首先对容量进行从大到小的排序, sor ...
- 使用freemarker导出word
最近需要将jsp部分页面导出为word文件,环境是Spring+SpringMVC+Hibernate. 我使用的是FreeMarker模板引擎来完成.这是FreeMarker的中文参考手册,感兴趣的 ...
- 第88讲:Scala中使用For表达式实现map、flatMap、filter
今天我们来学习一下如何使用for表达式实现map.flatMap以及filter 首先,我们来看下map.map的功能是,传入一个list,通过一个函数f,将list中的元素A变成元素B的过程.最后得 ...
- express4.x socket
在这个版本下使用socket,配置比较麻烦. 使用实例:http://www.open-open.com/lib/view/open1402479198587.html 配置文件:BarOrderPr ...
- 中大 9095. Islands
9095. Islands 限制条件 时间限制: 2 秒, 内存限制: 256 兆 题目描述 Whenever it rains, Farmer John's field always ends up ...
- myeclipse6.6+maven跑springside4.1的demo
1.安装myeclipse6.6 2.myeclipse6.6安装maven 2.1 删除原有maven. 关闭Eclipse程序, 进入MyEclipse插件目录/eclipse/features ...
- Excel函数vlookup
最近整理业务文档,需要用到excel,按照教程,操作了20来分钟,却得不到结果. 看了视频,才知道,vlookup仅限关联选中区域的第一列关联,把要关联的行拷贝到第一列,解决. https://www ...