.NET Framework泛型是一个很强大的新特性,它为每一种对象生成一份单独的代码(也就是所谓的“实例化”),这一份量身顶做的代码具有很高的效率,是强类型的,不需要运行期多态的支持和负担,有了泛型,就不再需要Object类来参与实现一些通用类或方法了.
.NET Framework泛型的作用在CLR(common language runtime)1.0中,当要创建一个灵活的类或方法,但该类或方法在编译期问不知道使用什么类,就必须以System.Object类为基础进行处理,而Object类在编译期间没有类型安全性,又必须进行强制类型转换.另外,给值类型使用Object类会有性能损失,这给程序开发带来诸多不便.故在CLR 2.0(.NET 3.5基于CLR 2.0)中,提供了泛型.
通过使用泛型类型,可以根据需要,用特定的类型替换泛型类型,同时保证了类型安全性:如果某个类型不支持泛型类,编译器就会报错,以阻止程度发生运行期错误.正确使用泛型将大大提高代码的灵活性,结合一个优秀的设计模式,可以显著缩短开发时间.
泛型的优势安 全C#是一个类型安全的语言,类型安全允许编译器(可信赖的)捕获潜在的错误,而不是在程序运行时才发现(不可信赖的).在CLR1.0中,当使用集合时,这种类型安全就失效了:由.NET类库提供的集合类全是存储基类型(Object)的,而.NET中所有的一切都继承于Object,因此所有类型都可以放到一个集合中,这相当于根本就没有了类型检测.下面的代码也正好说明了这个问题.
ArrayListlist—new ArrayI.ist():list.Add(100);list.Add(“test”);list.Add(new object());foreach(int i in list)//引发运行期错误Console.Write(i);可以往ArrayList里添加任何类型,也能通过编译,但是在接下来的使用中,由于字符串“test”和Object对象都不能转换为值类型int,这会抛出运行期错误,类型不再安全1.
性 能泛型的一个主要优点是性能.如果对值类型使用普通的集合类,在把值类型转换为引用类型和把引用类型转换成为值类型时,程序会进行装箱和拆箱操作,性能损失比较大,操作迭代多次时尤其严重。而使用泛型能使程序在运行期间明确知道操作的对象的类型,可以减少拆箱和装箱的操作。
ArrayList list—new Arraylist();liSt.Add(100);//装箱:将值类型转换为引用类型int i=(int)list[03;//拆箱:将引用类型转换为值类型 foreach(int j in list)//拆箱 Console.Write(j);Listiist=new List(); list.Add(100);//无装箱:类型已经存储在List int i—listE0];///无拆箱:不需要进行类型转换 foreach(int j in list) Console.Write(j);重 用泛型允许更好地重用代码.泛型类可以只定义一次,用于不同的类型实例化,减少代码量,如list, List,List等等,且泛型可以在一种语言中定义,在另一种.NET语言中使用(如C#,VB.NET等).泛型编译为II。(intermediate language)代码时,是采用占位符来表示泛型类型,并用专有的IL指令支持泛型操作,所以用某个类型实例化泛型不会在IL代码中复制这些类.为了说明,使用一个最简单的泛型类class Test{...},编译运行后,使用Visual Studio自带的IL反汇编程序打开生成的可执行文件,定位到Test类的构造函数,可以看到下面的代码:
.method public hidebysig specialname rtspecialname instance void.ctor(!T 7value')cil managed{ IL-000a:stfld ! 0 class last.7Fest、1::-object}可以看出,泛型类使用了占位符“T”来表示这个泛型所支持的类型参数,并不会生成多份Test类以适应不同的传人类型.
真正的泛型实例化工作以“on-demand”的方式发生在JIT(Just—in time)编译时,CLR为所有类型参数为“引用类型”的泛型类产生同一份代码;但是如果类型参数为“值类型”,对每一个不同的“值类型”,CLR将为其产生一份独立的代码.
常用泛型可空类型C#中的值类型必须包含一个值,而引用类型可以为空(null),但是让值类型可空是非常有用的(配合数据库使用).所以,.NET提供了泛型System.Nullable可以使值类型具备可空的性质,其中类型参数T必须是不可以为null的类型.因为可空类型使用得非常频繁,所以C#有一种特殊的语法,使用“?”运算符,用于定义这种类型的变量,如int7.
泛型集合System.Collection.Generic命名空间下有大量泛型集合类_J,图1列示了几个比较常用的泛型,它们使用起来都十分方便,.NET已经为这些类提供了完善的成员函数与属性.
泛型的继承.NET已有的泛型的功能已经比较完善,但是如果想在其基础上增加自定义的操作,可以定义一个泛型类并继承.NET已有的泛型,见图2.
需要注意的是,如果某个类型在它所继承的基类型中受到约束,该类型就不能“解除约束”.也就是说,类型参数丁在基类中使用受到了某约束S,则在子类中T必须受到至少与基类型相同的约束.
本词条内容贡献者为:
王慧维 - 副研究员 - 西南大学