1.前言
泛型(Generic)的优点主要体现在提升性能和类型安全两方面,下面将对这两点进行分析。
2.提升性能
通过编写一个使用 .NET 类库中 ArrayList 集合类的小程序,可体现出使用非泛型集合类的局限。 ArrayList 类的实例可以存储任何引用或值类型。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
System.Collections.ArrayList list1 = new System.Collections.ArrayList();
list1.Add(3);
list1.Add(105);
System.Collections.ArrayList list2 = new System.Collections.ArrayList();
list2.Add("It is raining in Redmond.");
list2.Add("It is snowing in the mountains.");
但这种便利有一定代价。 添加到 ArrayList 的任何引用或值类型均隐式向上转换为 Object。 如果项为值类型,将它们添加到列表时必须将其装箱,检索它们时必须取消装箱。 转换与装箱/取消装箱这两种操作都会降低性能;在必须循环访问大型集合的方案中,装箱与取消装箱的影响非常大。
下面创建一个的示例,查看两者的 IL 代码,示例代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Test
{
static void ArrayDemo()
{
ArrayList arrayList = new ArrayList();
arrayList.Add(12);
Console.WriteLine(arrayList[0]);
}
static void GenericDemo()
{
List<int> list = new List<int>();
list.Add(12);
Console.WriteLine(list[0]);
}
static void Main()
{
ArrayDemo();
GenericDemo();
}
}
ArrayList 类型的 IL 代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
.method private hidebysig static void ArrayDemo() cil managed
{
// Code size 35 (0x23)
.maxstack 2
.locals init ([0] class [mscorlib]System.Collections.ArrayList arrayList)
IL_0000: nop
IL_0001: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldc.i4.s 12
IL_000a: box [mscorlib]System.Int32
IL_000f: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
IL_0014: pop
IL_0015: ldloc.0
IL_0016: ldc.i4.0
IL_0017: callvirt instance object [mscorlib]System.Collections.ArrayList::get_Item(int32)
IL_001c: call void [mscorlib]System.Console::WriteLine(object)
IL_0021: nop
IL_0022: ret
} // end of method Test::ArrayDemo
泛型 List<int> 的 IL 代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
.method private hidebysig static void GenericDemo() cil managed
{
// Code size 30 (0x1e)
.maxstack 2
.locals init ([0] class [mscorlib]System.Collections.Generic.List`1<int32> list)
IL_0000: nop
IL_0001: newobj instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldc.i4.s 12
IL_000a: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
IL_000f: nop
IL_0010: ldloc.0
IL_0011: ldc.i4.0
IL_0012: callvirt instance !0 class [mscorlib]System.Collections.Generic.List`1<int32>::get_Item(int32)
IL_0017: call void [mscorlib]System.Console::WriteLine(int32)
IL_001c: nop
IL_001d: ret
} // end of method Test::GenericDemo
可以比较看出,通过创建泛型类型可以减少拆箱装箱的操作,从而提高性能。
3.类型安全
另一局限是缺少编译时类型检查;由于 ArrayList 将所有内容都转换为 Object,因此在编译时无法阻止客户端代码执行如下操作:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
System.Collections.ArrayList list = new System.Collections.ArrayList();
// Add an integer to the list.
list.Add(3);
// Add a string to the list. This will compile, but may cause an error later.
list.Add("It is raining in Redmond.");
int t = 0;
// This causes an InvalidCastException to be returned.
foreach (int x in list)
{
t += x;
}
虽然在创建异类集合时这完全可以接受,甚至有时是有意为之,但将字符串和 ints 合并到单个 ArrayList 中更有可能属于编程错误,且此错误在运行时之前不会被检测出。
而在使用泛型类型的时候会使用占位符 <T> 为其指定类型,在创建实例后保证其类型安全。