泛型的优点

1.前言

泛型(Generic)的优点主要体现在提升性能和类型安全两方面,下面将对这两点进行分析。

2.提升性能

通过编写一个使用 .NET 类库中 ArrayList 集合类的小程序,可体现出使用非泛型集合类的局限。 ArrayList 类的实例可以存储任何引用或值类型。

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.");
View Code

但这种便利有一定代价。 添加到 ArrayList 的任何引用或值类型均隐式向上转换为 Object。 如果项为值类型,将它们添加到列表时必须将其装箱,检索它们时必须取消装箱。 转换与装箱/取消装箱这两种操作都会降低性能;在必须循环访问大型集合的方案中,装箱与取消装箱的影响非常大。

下面创建一个的示例,查看两者的 IL 代码,示例代码如下:

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();
    }
}
View Code

ArrayList 类型的 IL 代码如下:

.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
View Code

泛型 List<int> 的 IL 代码如下:

.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
View Code

可以比较看出,通过创建泛型类型可以减少拆箱装箱的操作,从而提高性能。

3.类型安全

另一局限是缺少编译时类型检查;由于 ArrayList 将所有内容都转换为 Object,因此在编译时无法阻止客户端代码执行如下操作:

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;
}
View Code

虽然在创建异类集合时这完全可以接受,甚至有时是有意为之,但将字符串和 ints 合并到单个 ArrayList 中更有可能属于编程错误,且此错误在运行时之前不会被检测出。

而在使用泛型类型的时候会使用占位符 <T> 为其指定类型,在创建实例后保证其类型安全。

posted @ 2018-10-24 13:06  Kyle0418  阅读(1521)  评论(0编辑  收藏  举报