先说一下非泛型集合的问题
1、使用System.Collection和System.Collections.Specilizes的类导致低性能的代码,特别是在操作数值型数据时(如值类型)。当你在一个操作System.Object的非泛型集合类中存储结构时,CLR必须执行大量的内存转换工作,降低运行速度。
2、经典的集合不是类型安全的,因为他们是为了操作Systm.Object类而开发的,因此可以包含任意类型。
性能问题
.NET平台支持两大数据类型:值类型和引用类型。由于.NET定义了这两大类型,我们有时需要用装箱和拆箱来实现用一个类别的变量来表示另一个类别的变量。尽管装箱和拆箱对程序员来说很方便,但这种方式带来的的堆/栈内存转移会导致性能问题,并且也缺乏类型安全。我们可以看看装箱和拆箱一个整数时发生的步骤:
1必须在托管堆上分配一个新对象。
2基于栈数据的值必须被转移到新分配的内存位置。
3在拆箱时,保存在堆对象中的值必须转移回栈。
4堆上无用的对象最后会被回收。
理想情况下,我们应该可以在没有任何性能问题的容器中操作堆栈数据,并且在获取数据时也不必使用try/catch作用域(这正是泛型所实现的)。
类型安全问题
由于Sytem.Collections中的大多数类所操作的都是System.Object,因此他们可以容纳任何类型。大多数情况下,我们需要一个类型安全的容器来操作特定的数据类型,例如你可能需要只能容纳数据库连接,位图或Ipointy兼容对象的容器。在泛型之前,要解决类型安全问题的唯一方法是手工创建自定义(强类型)集合类。虽然自定义的集合可以确保类型安全,但是如果使用这个方法,就必须为每一个希望包含的类型创建一个(基本一样)自定义集合。然而这些自定义集合并没有消除装箱/拆箱的损失。
public class IntCollection : IEnumerable { private ArrayList arInts = new ArrayList(); //为调用者拆箱 public int GetInt(int pos) { return (int)arInts[pos]; } //装箱操作 public void AddInt(int i) { arInts.Add(i); } public void ClearInts() { arInts.Clear(); } public int Count { get { return arInts.Count; } } IEnumerator IEnumerable.GetEnumerator() { return arInts.GetEnumerator(); } }
不管使用哪个类型来保存整数,我们都不能避免使用非泛型容器带来的装箱问题。
泛型集合
使用泛型集合类可以解决上面所有的问题,包括拆箱/装箱和类型安全缺失。另外基本上不需要用手工构建自定义(泛型)集合类。考虑如下的方法,他是用泛型List<T>类(System.Collections.Generic命名空间)以强类型的方式保存不同的类型。
static void UseGenneriList() { Console.WriteLine("**** Fun with Genneris ****\n"); //该List<>只能容纳Person类 List<Person> morePeople = new List<Person>(); morePeople.Add(new Person("Frank", "Black", 50)); Console.WriteLine(morePeople[0]); //该List<>只能容纳整数 List<int> moreInts = new List<int>(); moreInts.Add(10); moreInts.Add(2); int sum = moreInts[0] + moreInts[1]; //编译时错误!不能讲Person对象添加到整形列表中 //moreInts.Add(new Person()); Console.ReadKey(); } public class Person { public Int32 Age { get; set; } public String FirstName { get; set; } public String LastName { get; set; } public Person(){} public Person(String firstName,String lastName ,Int32 age) { Age=age; FirstName = firstName; LastName = lastName; } public override string ToString() { return String.Format("Name:{0},{1},Age:{2}", FirstName, LastName, Age); } }
第一个List<T>对象只能包含Person对象。因此,在从容器中获取项时不必进行转换,这使得这种方法更加类型安全。第二个List<T>只能包含整数,所有的整数都分配在栈上。与非泛型容器相比,泛型具有以下优势:
1泛型提供了更好的性能,因为它们不会导致装箱或拆箱的损耗。
2泛型更加类型安全,因为它们只包含我们指定的类型。
3泛型大幅减少了构建自定义集合类型的需求,因为当创建了泛型容器时指定了“类型的类型”。
泛型参数的作用
只有类,结构,接口和委托可以使用泛型,枚举类型不可以。
(未完待续)