泛型特性及内部机制

2.0 版 C# 语言和公共语言运行库 (CLR) 中增加了泛型。泛型将类型参数的概念引入 .NET Framework,类型参数使得设计如下类和方法成为可能:这些类和方法将一个或多个类型的指定推迟到客户端代码声明并实例化该类或方法的时候。例如,通过使用泛型类型参数 T,您可以编写其他客户端代码能够使用的单个类,而不致引入运行时强制转换或装箱操作的成本或风险。(MSDN)

特性1、类型安全编译器防止它成为运行时源码的bug,这是一件非常美妙的事情。

public class GenericClass<T>
{
    
static int _count = 0;
    
int _maxItemCount;
    T[] _items;
    
int _currentItem = 0;
    
public GenericClass(int items)
    
{
        _count
++;
        _ _maxItemCount 
= items;
        _items 
= new T[_maxItemCount];
    }

    
public int AddItem(T item)
    
{
        
if (_currentItem < _maxItemCount)
        
{
            _items[_currentItem] 
= item;
            
return _currentItem++;
        }

        
else
            
throw new Exception("Item queue is full");
    }

    
public T GetItem(int index)
    
{
        Debug.Assert(index 
< _maxItemCount);
        
if (index >= _maxItemCount)
            
throw new ArgumentOutOfRangeException("index");
        
return _items[index];
    }

    
public int ItemCount
    
{
        
get return _currentItem; }
    }

    
public override string ToString()
    
{
        
return "There are " + _count.ToString() +
           
" instances of " + this.GetType().ToString() +
           
" which contains " + _currentItem + " items of type " +
           _items.GetType().ToString() 
+ "";
    }

}
 
       // 泛型类
    GenericClass<string> gC = new GenericClass<string>(5);
    Console.WriteLine(gC);
    
string s1 = "s1";
    
string s2 = "s2";
    
string s3 = "s3";
    
int i1 = 1;
    
// 把字符串添加进泛型类.
    gC.AddItem(s1);
    gC.AddItem(s2);
    gC.AddItem(s3);
    
// 尝试在字符串实例中添加整数,将被编译器拒绝
    
// error CS1503: Argument '1': cannot convert from 'int' to 'string'
   
//GC.AddItem(i1); 

特性2、避免装箱、拆箱 

典型的例子就是应用ArrayList<T>而不是ArrayList。 


泛型机制1、编译及运行机制

C#泛型能力由CLR在运行时支持,区别于C++的编译时模板机制,和Java的编译时“茶匙发”,这使得泛型能力可以在各个支持CLR的语言之间进行无缝互操作。C#泛型代码在被编译为IL代码和元数据时,采用特殊的占位符来表示泛型类型,并用专有的IL指令支持泛型操作。而真正的泛型实例化工作以 "on-demand" 的方式,发生在JIT编译时。

我们从C#总定义一段基本的范型代码开始 

   1: public class GenericType<T> : IComparable<T>, IComparable<GenericType<T>>
   2:                     where T: IComparable
   3: {
   4:     public T Value;
   5:     
   6:     public int CompareTo(T t)
   7:     {
   8:         return this.Value.CompareTo(t);
   9:     }
  10:     
  11:     public int CompareTo(GenericType<T> t)
  12:     {
  13:         return this.Value.CompareTo(t.Value);
  14:     }

15: } 

反编译后的IL代码 
   1: .class public auto ansi beforefieldinit GenericType`1<([mscorlib]System.IComparable) T>
   2:        extends [mscorlib]System.Object
   3:        implements class [mscorlib]System.IComparable`1<!T>,
   4:                   class [mscorlib]System.IComparable`1<class GenericType`1<!T>>
   5: {
   6:   .field public !T Value
   7:   .method public hidebysig newslot virtual final 
   8:           instance int32  CompareTo(!T t) cil managed
   9:   {
  10:     // Code size       24 (0x18)
  11:     .maxstack  8
  12:     IL_0000:  ldarg.0
  13:     IL_0001:  ldflda     !0 class GenericType`1<!T>::Value
  14:     IL_0006:  ldarg.1
  15:     IL_0007:  box        !T
  16:     IL_000c:  constrained. !T
  17:     IL_0012:  callvirt   instance int32 [mscorlib]System.IComparable::CompareTo(object)
  18:     IL_0017:  ret
  19:   } // end of method GenericType`1::CompareTo
  20:  
  21:   .method public hidebysig newslot virtual final 
  22:           instance int32  CompareTo(class GenericType`1<!T> t) cil managed
  23:   {
  24:     // Code size       29 (0x1d)
  25:     .maxstack  8
  26:     IL_0000:  ldarg.0
  27:     IL_0001:  ldflda     !0 class GenericType`1<!T>::Value
  28:     IL_0006:  ldarg.1
  29:     IL_0007:  ldfld      !0 class GenericType`1<!T>::Value
  30:     IL_000c:  box        !T
  31:     IL_0011:  constrained. !T
  32:     IL_0017:  callvirt   instance int32 [mscorlib]System.IComparable::CompareTo(object)
  33:     IL_001c:  ret
  34:   } // end of method GenericType`1::CompareTo
  35:  
  36:   .method public hidebysig specialname rtspecialname 
  37:           instance void  .ctor() cil managed
  38:   {
  39:     // Code size       7 (0x7)
  40:     .maxstack  8
  41:     IL_0000:  ldarg.0
  42:     IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
  43:     IL_0006:  ret
  44:   } // end of method GenericType`1::.ctor
  45:  

46: } // end of class GenericType`1 

一轮编译时,编译器只为Stack<T>类型产生"泛型版"IL代码与元数据——并不进行泛型类型的实例化,T在中间只充当占位符JIT编译时,当JIT编译器第一次遇到Stack<int>时,将用int替换"泛型版"IL代码与元数据中的T——进行泛型类型的实例化。CLR为所有类型参数为"引用类型"的泛型类型产生同一份代码;但如果类型参数为"值类型",对每一个不同的"值类型"CLR将为其产生一份独立的代码。 

泛型机制2、泛型约束

C#泛型要求对"所有泛型类型或泛型方法的类型参"的任何假定,都要基于"显式的约束",以维护C#所要求的类型安全。"显式约束"where子句表达,可以指定"基类约""接口约束""构造器约束""值类型/引用类型约束"共四种约束。"显式约束"并非必须,如果没有指定"显式约束"泛型类型参数将只能访问System.Object类型中的公有方法。 

参考资料:

1、泛型基类的应用 

http://www.cnblogs.com/XmNotes/archive/2012/04/23/2466938.html  

2、泛型的机制(IL)

http://www.2cto.com/kf/201204/129457.html  

3、泛型的相关书藉描述

http://www.cnblogs.com/abatei/archive/2008/02/20/1075760.html  
原文地址:https://www.cnblogs.com/malaikuangren/p/2506991.html