本文是根据网上&书本总结来的。

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# 深入了解泛型的更多相关文章

  1. 一起学 Java(三) 集合框架、数据结构、泛型

    一.Java 集合框架 集合框架是一个用来代表和操纵集合的统一架构.所有的集合框架都包含如下内容: 接口:是代表集合的抽象数据类型.接口允许集合独立操纵其代表的细节.在面向对象的语言,接口通常形成一个 ...

  2. .NET面试题系列[8] - 泛型

    “可变性是以一种类型安全的方式,将一个对象作为另一个对象来使用.“ - Jon Skeet .NET面试题系列目录 .NET面试题系列[1] - .NET框架基础知识(1) .NET面试题系列[2] ...

  3. C#4.0泛型的协变,逆变深入剖析

    C#4.0中有一个新特性:协变与逆变.可能很多人在开发过程中不常用到,但是深入的了解他们,肯定是有好处的. 协变和逆变体现在泛型的接口和委托上面,也就是对泛型参数的声明,可以声明为协变,或者逆变.什么 ...

  4. 编写高质量代码:改善Java程序的151个建议(第7章:泛型和反射___建议106~109)

    建议106:动态代理可以使代理模式更加灵活 Java的反射框架提供了动态代理(Dynamic Proxy)机制,允许在运行期对目标类生成代理,避免重复开发.我们知道一个静态代理是通过主题角色(Prox ...

  5. 6.在MVC中使用泛型仓储模式和依赖注入实现增删查改

    原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/crud-operations-using-the-generic-repository-pat ...

  6. C#泛型详解(转)

    初步理解泛型: http://www.cnblogs.com/wilber2013/p/4291435.html 泛型中的类型约束和类型推断 http://www.cnblogs.com/wilber ...

  7. C# 泛型

    C# 泛型 1.定义泛型类 在类定义中包含尖括号语法,即可创建泛型类: class MyGenericClass<T> { //Add code } 其中T可以遵循C#命名规则的任意字符. ...

  8. java8中lambda表达式的应用,以及一些泛型相关

    语法部分就不写了,我们直接抛出一个实际问题,看看java8的这些新特性究竟能给我们带来哪些便利 顺带用到一些泛型编程,一切都是为了简化代码 场景: 一个数据类,用于记录职工信息 public clas ...

  9. java 泛型

    1.Student stu =tool.getObj();右边得到的是Object类型,需要向下转型,强转换. 2. 3. 4.泛型方法不能被静态修饰这样写 5.如果想定义定义静态泛型方法,只能这样写 ...

  10. Java泛型的历史

    为什么Java泛型会有当前的缺陷? 之前的章节里已经说明了Java泛型擦除会导致的问题,C++和C#的泛型都是在运行时存在的,难道Java天然不支持“真正的泛型”吗? 事实上,在Java1.5在200 ...

随机推荐

  1. 按自己的想法去理解事件和泛型(C#)

    上一篇那些年困扰我们的委托(C#)讲了委托,这一篇自然就轮到事件了. 不喜欢官方的表达方式,喜欢按照自己的想法去理解一些抽象的东西. 事件 考虑到委托使用的一些缺陷,就有了事件.委托是不安全的,打个比 ...

  2. C语言之总结3

    23). 内存中的五大区域 a. 栈 是专门用来存储局部变量的.所有的局部变量都是声明在栈区域中的. b. 堆 允许程序员手动的从堆申请空间来使用.(对象) c. BSS段 是用来存储未初始化的全局变 ...

  3. 在Openstack上创建并访问Kubernetes集群

    第一部分:创建集群 在Openstack部署Kubernetes集群运行Nginx容器的步骤,其中包括: 利用Murano部署Kubernetes集群 配置Openstack的安全性使Kubernet ...

  4. 删除style的样式JQuery

      有些页面样式不规范,没有写在一个class里,例如:<div id="show" style="width:100px; padding-top:10px; f ...

  5. Kafka connect快速构建数据ETL通道

    摘要: 作者:Syn良子 出处:http://www.cnblogs.com/cssdongl 转载请注明出处 业余时间调研了一下Kafka connect的配置和使用,记录一些自己的理解和心得,欢迎 ...

  6. 证据权模型(C#版)

    证据权法是通过计算和利用各种不同证据的权重(表示相对重要性)并将多种证据结合起来,预测某个时间是否会发生的一种方法 证据权法以概率论中的贝叶斯定理为基础.设D表示要一个随机事件.用P(D)表示这一事件 ...

  7. USACO 4.1 Beef McNuggets

    Beef McNuggetsHubert Chen Farmer Brown's cows are up in arms, having heard that McDonalds is conside ...

  8. Kattis - Fenwick Tree(树状数组区间更新单点求值)

    Fenwick Tree Input The first line of input contains two integers NN, QQ, where 1≤N≤50000001≤N≤500000 ...

  9. ProgrammingContestChallengeBook

    POJ 1852 Ants POJ 2386 Lake Counting POJ 1979 Red and Black AOJ 0118 Property Distribution AOJ 0333 ...

  10. 【1】Hover 效果收集

    各种 hover 效果  github repository>>  git 仓库 1. 背景图的 hover 效果 原页面>> githubSite>>