C# 深入了解泛型
本文是根据网上&书本总结来的。
1. 介绍
泛型程序设计是程序设计语言的一种风格或范式。 泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时(instantiate)作为参数指明这些类型。
.NET Framework泛型的参数只可以代表类,不能代表个别对象。由于.NET Framework泛型的类型参数之实际类型在运行时均不会被消除,运行速度会因为类型转换的次数减少而加快。另外,使用GetType()
方法可于程序运行时得知泛型及其类型参数的实际类型,更可以运用反射编程。
2. 为什么需要泛型
任何API只要将object作为参数类型或返回类型使用,就可能在某个时候涉及强制类型转换。设计只有一个类,并将object作为根的层次结构,将使一切变得更加简单。但是,object类型本身是极其‘愚钝’的一个存在。要用一个object做真正有意义的事情,几乎都要对它进行强制类型转换。
泛型能对性能有增强的作用,首先编译器能执行更多的检查,所以执行时的检查可以少做。其次,JIT能够聪明地处理值类型,能消除很多情况下的装箱和拆箱处理。某些情况下,无论在速度上还是在内存消耗上,有泛型和没有泛型的结果会大相径庭。
泛型带来的好处非常像静态语言较之动态语言的优点:更好的编译时检查,更多在代码中能直接表现的信息,更多的IDE支持,更好的性能。原因很简单,使用一个不能区分不同类型的常规API(比如ArrayList),相当于在一个动态环境中访问那个API。顺便说一下,反过来说通常不成立:动态语言在许多情况下都具备大量的优势,但这些情况很少适用于选择泛型和非泛型的API。当你能合理地使用泛型时,通常会毫不犹豫地选择泛型。
3. 我们通过例子来学习
1)我们用泛型来创建一个创建List的方法:
- public List<T> MakeList<T>(T a, T b)
- {
- return new List<T>() {a, b};
- }
List<string> myList = MakeList("str1", "str2");
从上面的例子可以看出,只要我们传入自己的类型,就能创造返回自己的类型了。
2)现在我们深入一点。
就像实例字段从属于一个实例一样,静态字段从属于声明他们的类型。如果在SomeClass中声明了静态字段x,不管创建SomeClass的多少个实例,也不管从SomeClass派生出多少个类型,都只有一个SomeClass.x字段。
每个封闭类型都有它自己的静态字段集。我们为不同的封闭类型设置字段的值,然后打印这些值,证明它们是各自独立的。
- public class TypeWithField<T>
- {
- public static string field;
- public static void PrintField()
- {
- Console.WriteLine(field +": " + typeof(T).Name);
- }
- }
下面我们打印它们的值:
- TypeWithField<int>.field = "f1";
- TypeWithField<string>.field = "s2";
- TypeWithField<DateTime>.field = "t3";
- TypeWithField<int>.PrintField();
- TypeWithField<string>.PrintField();
- TypeWithField<DateTime>.PrintField();
可以看到有这些值:
所以,基本规则是:每个封闭类型又一个静态字段。同样的规则也适用于静态初始化程序和静态构造函数。然而,一个泛型类型可能嵌套在另一个泛型类型中,而且一个类型可能有多个泛型参数。虽然听起来很复杂,但它的工作方式与你想象的差不多。
4. JIT编译器如何处理泛型
对于所有不同的封闭类型,JIT的职责就是将泛型的IL转换成本地代码,使其能真正运行起来。从某些方面来说,我们并不需要知道具体的转换过程是怎么样的。只需要留意内存和CPU时间即可。如果JIT为每个封闭类型都单独生成本地代码,就像这些类型相互之间没有任何联系一样,我们将不会感觉出太大差异的。但是JIT的作者十分聪明,非常有必要看看他们做了什么。
首先看一个简单的、只有一个类型参数的情况。为方便讨论,我们使用List<T>作为例子。JIT为每个以值类型作为类型实参的封闭类型都创建不同的代码。然而,所有使用引用类型(string、Stream、StringBuilder等)作为类型实参的封闭类型都共享相同的本地代码。之所以能这样做,是由于所有引用都具有相同的大小(32位CLR上是4字节,64位CLR上是8字节。但是,在任何一个特定的CLR中,所有引用都具有相同的大小)。无论实际引用的是什么,引用(构成的)数组的大小是不会发生变化的。栈上引用所需的空间始终是相同的。无论使用的类型是什么,都可以使用相同的寄存器优化措施,即使是List<Reason>也不例外。
如上面所述,每个类型还可以有它自己的静态字段,但可执行代码本身是可以重用的。当然,JIT采用的仍然是‘懒人’原则。除非需要,否则不会为List<int>生成代码。而一旦生成代码,代码就会缓存起来,以备将来再次使用List<int>。
理论上,至少对一些值类型来说,代码是可以共享的。但JIT必须十分谨慎,不仅要考虑到大小,还要考虑到垃圾回收的问题,JIT必须能快速识别一个struct值中的引用是否是活着的。然而假如值类型具有相同的大小,而且就GC看来具有相同的‘内存需求量’,那么是应该能够共享代码的。
可以关注本人的公众号,多年经验的原创文章共享给大家。
C# 深入了解泛型的更多相关文章
- 一起学 Java(三) 集合框架、数据结构、泛型
一.Java 集合框架 集合框架是一个用来代表和操纵集合的统一架构.所有的集合框架都包含如下内容: 接口:是代表集合的抽象数据类型.接口允许集合独立操纵其代表的细节.在面向对象的语言,接口通常形成一个 ...
- .NET面试题系列[8] - 泛型
“可变性是以一种类型安全的方式,将一个对象作为另一个对象来使用.“ - Jon Skeet .NET面试题系列目录 .NET面试题系列[1] - .NET框架基础知识(1) .NET面试题系列[2] ...
- C#4.0泛型的协变,逆变深入剖析
C#4.0中有一个新特性:协变与逆变.可能很多人在开发过程中不常用到,但是深入的了解他们,肯定是有好处的. 协变和逆变体现在泛型的接口和委托上面,也就是对泛型参数的声明,可以声明为协变,或者逆变.什么 ...
- 编写高质量代码:改善Java程序的151个建议(第7章:泛型和反射___建议106~109)
建议106:动态代理可以使代理模式更加灵活 Java的反射框架提供了动态代理(Dynamic Proxy)机制,允许在运行期对目标类生成代理,避免重复开发.我们知道一个静态代理是通过主题角色(Prox ...
- 6.在MVC中使用泛型仓储模式和依赖注入实现增删查改
原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/crud-operations-using-the-generic-repository-pat ...
- C#泛型详解(转)
初步理解泛型: http://www.cnblogs.com/wilber2013/p/4291435.html 泛型中的类型约束和类型推断 http://www.cnblogs.com/wilber ...
- C# 泛型
C# 泛型 1.定义泛型类 在类定义中包含尖括号语法,即可创建泛型类: class MyGenericClass<T> { //Add code } 其中T可以遵循C#命名规则的任意字符. ...
- java8中lambda表达式的应用,以及一些泛型相关
语法部分就不写了,我们直接抛出一个实际问题,看看java8的这些新特性究竟能给我们带来哪些便利 顺带用到一些泛型编程,一切都是为了简化代码 场景: 一个数据类,用于记录职工信息 public clas ...
- java 泛型
1.Student stu =tool.getObj();右边得到的是Object类型,需要向下转型,强转换. 2. 3. 4.泛型方法不能被静态修饰这样写 5.如果想定义定义静态泛型方法,只能这样写 ...
- Java泛型的历史
为什么Java泛型会有当前的缺陷? 之前的章节里已经说明了Java泛型擦除会导致的问题,C++和C#的泛型都是在运行时存在的,难道Java天然不支持“真正的泛型”吗? 事实上,在Java1.5在200 ...
随机推荐
- Python基础1-变量、运算符、表达式
一.Python的安装 1.下载python安装包https://www.python.org/ 2.选择对应的Python版本(Windows下) 3.装完之后打开电脑的cmd,验证一下安装是否成功 ...
- 消息队列NetMQ 原理分析1-Context和ZObject
前言 介绍 NetMQ是ZeroMQ的C#移植版本,它是对标准socket接口的扩展.它提供了一种异步消息队列,多消息模式,消息过滤(订阅),对多种传输协议的无缝访问. 当前有2个版本正在维护,版本3 ...
- 关于Ueditor 前后端分离实现文件上传到独立服务器的问题 望大神们赐教
最近,由于网站实现多台服务器负载均衡,导致编辑器上传文件需要同步,可是使用同步软件太慢,不太现实,所以想到实现编辑器上传文件直接上传到独立文件服务器.可是没想到遇到坑了. 1.在本地IIS 中添加网站 ...
- 求a和b的最大公约数
题目:求a和b的最大公约数 分析:首先我们要知道最大公约数是什么,就是指两个或多个整数共有约数中最大的一个.好了,知道了最大公约数是什么,就可以求解它了,那么就相当于比较俩个数的约数,取其相等的最大的 ...
- 循序渐进看Java web日志跟踪(1)-Tomcat 日志追踪与配置
日志,是软件运行过程中,对各类操作中重要信息的记录. 日志跟踪,不管对于怎么样的项目来说,都是非常重要的一部分,它关系到项目后期的维护和排错,起着举足轻重的作用.项目开发过程中,对日志的记录规则,也将 ...
- android之控件与布局
基本控件:TextViewButtonEditTextImageViewAlertDialog.BubliderProgressDialog 四种基本布局的特殊属性: LinerLayout andr ...
- C# 实现客户端程序自动更新
看到一篇不错的帖子,可能以后会用到,果断收藏 文章来源 博客园jenry(云飞扬)http://www.cnblogs.com/jenry/archive/2006/08/15/477302.html ...
- Let's Encrypt(开源SSL证书管理工具)
刚装上一个StartSSL 的证书没几天,却看到官方发出这样的通知: 无聊中看到了网上各种相关的扯淡: http://tieba.baidu.com/p/4801786642 http://www.t ...
- Java 内部类 this
内部类访问外部类的一个例子: public class Abc { private class Bc { public void print() { System.out.println(Abc.th ...
- 绿色版的mysql安装配置方式
解压下载好的压缩包 copy 一份my-default.ini改名字为my.ini为mysql的配置文件 打开my.ini 修改配置文件 默认的原版文件为 # For advice on how to ...