基础巩固系列 (一)- 泛型(1)
1、泛型介绍
泛型是自.net framework 2.0以来就支持的。
泛型是类型安全的。
拥有了泛型,就可以创造出独立于被包含类型的类和方法了。也可以理解为,泛型就像是一个模板,常常定义一些通用的算法,具体调用时再替换成实际的数据类型,提高了代码的可重用性。
2、泛型的优缺点
⑴性能
泛型的一个主要优点就是性能。
在解释性能为什么是泛型的主要优点之前,我们还需要了解两个概念:
装箱:从值类型转换为引用类型。
拆箱:从引用类型转换为值类型。
var list = new ArrayList(); list.Add(44); //从值类型 转换为 引用类型 即装箱操作 int i = (int)list[0];//从引用类型 转换为 值类型 即拆箱操作
装箱和拆箱操作需要进行类型的转换,无疑增加了些操作的时间,对性能肯定也是有影响的,特别是对于大数据的类型转换操作。那么接下来看看泛型是怎么操作的吧。
//System.Collections.Generic 命名空间里面的List<T>在不使用对象,而是在使用时定义类型。 var list = new List<int>(); list.Add(44); //由于list在定义时使用了int类型,所以在此处添加int类型 不需要进行装箱操作 int i = list[0];//理由同上
System.Collections.Generic 命名空间里面的List<T>类不使用对象,而是在使用时定义类型。
⑵类型安全
泛型的另外一个特性是类型安全。看以下代码:
//自定义类型 class myclass { //此处省略 } var list = new ArrayList(); list.Add(1);//添加 整型对象 list.Add("黑色街角");//添加 字符串对象 list.Add(new myclass());//添加 自定义对象
对应ArrayList.Add(object value)方法,我们可以看到其参数为object类型对象,而object类是所有类的的基类,所有可以ArrayList.Add(object value)方法的参数可以是任意类型,以上运行也是这样的情况,但是对于下面这个呢?
//接上面代码 我们循环输出lis里面包含的t对象 foreach (int i in list) { Console.Write(i); }
我想结果可想而知,肯定是会报错的。因为字符串类型和以上的自定义类型是不可能转换为int型类型的。
那么接下来,我们看看泛型吧。
//泛型类型中已经定义了允许使用的类型为int类型 var list = new List<int>(); list.Add(1);//添加 int类型 是允许类型所以没有问题 list.Add("黑色街角");//添加 字符串对象 均会报错 list.Add(new myclass());//添加 自定义对象 均会报错
因为泛型类型在初始化的时候,就已经定义了允许使用的类型为int类型,而且你在调用list.Add方法的时候,聪明的你会发现里面的参数为(int item),所以这从根本上统一了类型,在后续的循环输出也就没有问题了。这也就是泛型的类型安全。
⑶二进制代码的重用
泛型允许很好的重用二进制代码。泛型类可以定义一次,并且可以使用不同的类型实例化。
例如:using System.Collections.Generic 命名空间里面的泛型类 List<T>类
var list = new List<int>();//int类型 实例化 list.Add(1); var stringlist = new List<string>();//字符串对象 实例化 stringlist.Add("黑色街角"); var myclasslist = new List<myclass>();//自定义对象 实例化 myclasslist.Add(new myclass());
泛型类型可以在一种语言中定义,在任何.NET语言中使用。
⑷代码的扩展
因为泛型类的定义会放在程序集中,所以用特定类型实例化泛型类不会再IL代码中复制这些类。但是,在JIT编译器把泛型类编译为本地代码时,会给每个值类型创建一个新类。引用类型共享同一个本地类的所有相同的实现代码。这是因为引用类型在实例化的泛型类中只需要4个字节的内存地址(32位操作系统),就可以引用一个引用类型。值类型包含在实例化的泛型类型的内存中,同时因为每个值类型对内存的要求有所不同,所以要为每个值类型实例化一个新类。
3、泛型的命名约定
泛型的命名规则:
泛型类型的名称用字母T作为前缀
如果没有什么特殊的要求,泛型类型允许用任意类型代替,且只使用一个泛型类型,就可以用字母T作为泛型类型的名称。
public class List<T> { } public class LinkedList<T> { }
如果泛型类型有特定的要求(例如:它必须实现一个接口或者派生自基类),或者使用两个或多个泛型类型,就应该给泛型类型使用描述性的名称。
public delegate void EventHander<TEventArags>(object sender,TEventArags e); public delegate Toutput Convert<Tinput,Toutput>(Tinput from); public class SortedList<Tkey, Tvalue> { }