1. 概述
泛型(generic)是CLR和编程语言提供的一种特殊机制,它支持另一种形式的代码重用,即“算法重用”。
泛型为开发人员提供了以下优势:
① 源代码保护。(针对C++的模板技术)
② 类型安全。
③ 更加清晰的代码。(减少转型次数)
④ 更佳的性能。(值类型无需装箱)
2. 名词解释
① 代码爆炸:泛型类型在编译时,CLR要为每种不同的方法/类型组合生成本地代码。它可能造成应用程序的工作集显著增大,影响性能。
3. 主要内容
3.1 Framework类库中的泛型
FCL定义的几个泛型集合类,大多数在 System.Collections.Generic 和 System.Collections.ObjectModel命名空间中。
要使用现成安全的集合类,可以去 System.Collections.Concurrent命名空间找寻。
System.Array类(所有数组类型的基类)提供了大量静态泛型方法。
3.2 Wintellect 的 Power Collections 库
Wintellect制作了Power Collections 库,使CLR程序员也能使用C++标准模板库(STL)的部分集合类。
3.3 泛型基础结构
3.3.1 开放类型和封闭类型
具有泛型类型参数的类型成为 开放类型,CLR 禁止构造开放类型的任何实例。
3.3.2 泛型类型和继承
泛型类型仍然是类型,所以它能从其他任何类型派生。
3.3.3 泛型类型同一性
3.3.4 代码爆炸
CLR内建了一些优化措施来缓解代码爆炸:
① 假如为一个特定的类型实参调用了一个方法,以后再次使用相同的类型实参来调用时,CLR只会为这个方法/类型组合编译一次代码。
② CLR认为所有引用类型实参都是完全相同的,所以代码能够共享。
3.4 泛型接口
一个引用类型或值类型可通过指定类型实参的方式来实现泛型接口,也可以保持类型实参的未指定状态来实现一个泛型接口。
3.5 泛型委托
3.6 委托和接口的逆变和协变 泛型类型实参(好拗口)
泛型类型参数可以是以下任何一种类型:
① 不变量(invariant): 意味着泛型类型参数不能更改。
② 逆变量(contravariant): 意味着泛型类型参数可以从一个基类更改为该类的派生类。(C#中用in标记,只能出现在输入位置。)
③ 协变量(covariant): 意味着泛型类型参数可以从一个派生类更改为它的基类。(C#中用out标记,只能出现在输出位置。)
public delegate TResult Func<in T, out TResult>(T arg);
3.7 泛型方法
CLR允许一个方法指定它独有的泛型参数。
C#编译器支持在调用一个泛型方法时进行 类型推断。
3.8 泛型和其他成员
C#中,属性、索引器、事件、操作符方法、构造器 和 终结器(finalizer)本身不能有泛型参数。
3.9 可验证性和约束
编译器和CLR支持 约束 机制,用来限制能指定成泛型实参的类型数量。
public static T Min<T>(T o1, T o2) where T : IComparable<T> { if (o1.CompareTo(o2) < 0) return o1; return o2; }
① 主要约束
泛型参数可以指定零个或者一个 主要约束。 主要约束可以是引用类型,它标识了一个没有密封的类。
两个特殊的主要约束:class 和 struct。
② 次要约束
泛型参数可以指定零个或者多个 次要约束,次要约束代表的是一个接口类型。
还有一种次要约束称为 类型参数约束。它允许一个泛型类型或方法规定:在指定的类型实参之间,必须存在一个关系。
③ 构造器约束
泛型参数可以指定零个或者一个 构造器约束,要求 一个指定的泛型实参是实现了公共无参构造器的一个非抽象类型。
④ 其他可验证性问题
*泛型类型变量的转型
*将一个泛型类型变量设为默认值。(T temp = default(T); );
*将一个泛型类型变量与null进行比较
*两个泛型类型变量相互比较
*泛型类型变量作为操作数使用
4. 总结