泛型
这两天又看了一些关于变体(协变和逆变)方面的博文,看的时候感觉的确讲的不错,很好理解,但看多了就会发现是越看越晕啊。以前也有做过这方面的总结,但总是过段时间就会脑子里一片空白,这该不会是太极剑的最高境界吧,呵呵,开个小玩笑。不过得先理解泛型
个人映像中的泛型:1.方法有输入参数(也可以有类型参数),泛型有类型参数;
2.泛型使用特定的类型代替类型参数;
3.泛型可以实现类型安全
4.泛型可以实现代码重用
从ArrayList到List<T>
var list = new ArrayList(); list.Add(1); foreach (int obj in list) { Console.WriteLine(obj); }
现在看看ArrayList的源码,找到 Add 这个方法:,这说明ArrayList存储的是对象,Add方法定义为需要把一个对象作为参数,所以要装箱一个整数类型,显然读取时要拆箱。装箱和拆箱使性能损失比较大。
好吧,那我用来存储一个对象(引用类型)呢?
public class Person { public string Say() { return "I am a nice man"; } }
var list = new ArrayList(); list.Add(new Person()); foreach (Person obj in list) { Console.WriteLine(obj.Say()); }
Ok,很好用,没有问题。但如果不慎像下面这样使用,在最后若传了个Japanese实例
public class Japanese{ ... }
var list = new ArrayList(); list.Add(new Person()); list.Add(new Japanese()); foreach (Person obj in list) { Console.WriteLine(obj.Say()); }
编译是能通过的(Add方法只负责接受Object,foreach为运行时迭代),但运行时,不幸抛异常了(Person和Japanese好像没有继承关系吧,至少在我的代码里)。foreach元素使用Person类型来迭代,很显然突然冒出来个Japanese,当然不知该如何是好。
C#是类型安全的语言,编译器可以捕捉到潜在的错误,而不是在运行时才以异常的方式呈现。显然我们这里需要一个类型参数,这个参数会告知编译器只接受某某类型的输入参数。请看泛型版本
List<Person> pList = new List<Person>(); pList.Add(new Person()); foreach (Person obj in list) { Console.WriteLine(obj.ToString()); }
使用Add方法添加元素时只接受Person类型,有截图、有真相
泛型可以实现代码重用
现在要用到一个存放Person对象的集合类,可以用下面的代码
public class PeronList :IEnumerable{ private int personCount; private ArrayList personArray; public PeronList(){ this.personCount = 0; this.personArray = new ArrayList(); } public int PersonCount { get{return this.personCount;} private set{this.personCount=value;} } public void Append(Person _Person){ this.personCount++; this.personArray.Add(_Person); } public Person indexOf(int index) { return (Person)this.personArray[index]; } public IEnumerator GetEnumerator() { for (int i = 0; i < this.personCount; i++) { yield return this.indexOf(i); } } }
是轻松完成了任务,且类型安全。假若又需要一个存放Animal对象的集合,So easy,这回不用动脑子了,直接Copy,Paste,then修该几个有类型修改的地方。但下回、下下回呢,不能总是麻烦自己的双手和浪费宝贵的时间吧,再说改动过程中又极有可能出现失误。
就不能有什么一劳永逸的解决办法么?当然是使用泛型List<T>啦,使用方式上面已经有啦。
泛型的使用
1.泛型类:泛型类使用类型参数来实现C#的类型安全和代码重用
2.泛型约束:是对类型参数的范围约束
3.泛型方法:类型参数用方法声明来定义,泛型方法是由于泛型没有必要应用于整个类,一般应用在某个静态方法中使用,同样泛型方法也可以有泛型约束
总结
泛型还是很好用的,使用方便,可以减少重复代码,实现类型安全,使用List<T>代替ArrayList是必然。在JIT编译器把泛型编译为本地代码时,会给每个类型参数为值类型的创建一个新类,为引用类型共享同一个本地类的所有实现代码。