泛型是2.0 版C# 语言和公共语言运行库(CLR) 中的一个新功能。泛型将类型参数的概念引入.NET Framework,类型参数使得设计如下类和方法成为可能:这些类和方法将一个或多个类型的指定推迟到客户端代码声明并实例化该类或方法的时候。例如,通过使用泛型类型参数T,您可以编写其他客户端代码能够使用的单个类,而不致引入运行时强制转换或装箱操作的成本或风险。

 

泛型类和泛型方法同时具备可重用性、类型安全和效率,这是非泛型类和非泛型方法无法具备的。

 

比较ArrayList

 

ArrayList 是一个使用起来非常方便的集合类,无需进行修改即可用来存储任何引用或值类型。

 

但这种方便是需要付出代价的。添加到ArrayList 中的任何引用或值类型都将隐式地向上强制转换为Object。如果项是值类型,则必须在将其添加到列表中时进行装箱操作,在检索时进行取消装箱操作。强制转换以及装箱和取消装箱操作都会降低性能;在必须对大型集合进行循环访问的情况下,装箱和取消装箱的影响非常明显。

 

另一个限制是缺少编译时类型检查;因为ArrayList 将把所有项都强制转换为Object,所以在编译时无法防止客户端代码bug。

 

与ArrayList 相比,使用List<T> 时添加的唯一语法是声明和实例化中的类型参数。虽然这稍微增加了些编码的复杂性,但好处是您可以创建一个比ArrayList 更安全并且速度更快的列表,特别适用于列表项是值类型的情况。

 

T:结构

类型参数必须是值类型。可以指定除Nullable 以外的任何值类型。有关更多信息,请参见使用可空类型(C# 编程指南)。

T:类

 类型参数必须是引用类型,包括任何类、接口、委托或数组类型。

T:new()

 类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。

T:<基类名>

 类型参数必须是指定的基类或派生自指定的基类。

T:<接口名称>

 类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。

T:U

 为T 提供的类型参数必须是为U 提供的参数或派生自为U 提供的参数。这称为裸类型约束。

 

泛型类封装不是特定于具体数据类型的操作。泛型类最常用于集合,如链接列表、哈希表、堆栈、队列、树等,其中,像从集合中添加和移除项这样的操作都以大体上相同的方式执行,与所存储数据的类型无关。创建泛型类的过程为:从一个现有的具体类开始,逐一将每个类型更改为类型参数,直至达到通用化和可用性的最佳平衡。

 

在泛型类和泛型方法中产生的一个问题是,在预先未知以下情况时,如何将默认值分配给参数化类型T:T 是引用类型还是值类型。如果T 为值类型,则它是数值还是结构。给定参数化类型T 的一个变量t,只有当T 为引用类型时,语句t = null 才有效;只有当T 为数值类型而不是结构时,语句t = 0 才能正常使用。解决方案是使用default 关键字,此关键字对于引用类型会返回空,对于数值类型会返回零。对于结构,此关键字将返回初始化为零或空的每个结构成员,具体取决于这些结构是值类型还是引用类型。