【IT168 技术文档】泛型早在.net2.0就出来了,大家已经对它的使用很熟悉了,在工作中也大量的使用过它,但是大家对其工作原理,以及MS针对泛型对CLR做了那些工作是否了解呢。本文就是对泛型的本质进行讲解,希望能对大家有所帮助。
1.引入泛型
.Net2.0出来的时候,大家很轰动,其中.NET2.0做的一个很大的改变就是增加了泛型。在1.1的版本,大家还在使用一些如:ArrayList等集合。就算现在是.net3.5的时代,还是有很多程序员在继续使用1.1版本的集合,并没有采用范型集合,毕竟一个新技术的使用是要一段时间的,也许大家看了本文后会在适当的时候使用范型。
List<int> arr1 = new List<int>();
for (int i = 1; i < 10; i++)
{
arr.Add(i);
arr1.Add(i);
}
这是一个很基础的泛型应用,可能大家大部分使用泛型都是类似上面的方式。我们就从这个简单的代码讲起。表面上看好像1.1版本和2.0版本的集合使用上没什么其别,一样的方便。但是实质上MS在底层做了很多复杂的工作。我们看看它的IL代码:
IL_0013: ldloc.2
IL_0014: box [mscorlib]System.Int32
IL_0019: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
IL_001e: pop
IL_001f: ldloc.1
IL_0020: ldloc.2
IL_0021: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
在这里我们看看它第三行,熟悉IL的人都知道。这行box是在执行装箱操作。我们可以看看的Add方法原型:
public virtual int Add(Object value) {
if (_size == _items.Length) EnsureCapacity(_size + 1);
_items[_size] = value;
_version++;
return _size++;
}
List:
public void Add(T item) {
if (_size == _items.Length) EnsureCapacity(_size + 1);
_items[_size++] = item;
_version++;
}
我们可以看到ArrayList的Add方法的参数是object类型,我们都知道int --> object是要经过装箱操作,装箱操作又是个很费时间的事情,这就影响了性能。这里我们就引出泛型的第一个好处:性能的好处,避免了频繁的装箱拆箱操作。泛型的第二个好处:保证了类型的绝对安全,这点就不多讲了。上面的IL里多了一个类型:System.Collections.Generic.List`1这是.net CLR为泛型生成一个带“'”的类型,后面的数字表示<x,x>里参数x的个数。还有一个就是!0,这个是什么呢,请看下面的分析。