CLR允许创建 generic reference types 以及generic value types, 但是不允许创建 generic enumerated types.
代码爆炸
当一个使用泛型参数的方法被JIT编译时,CLR取出方法的中间语言(IL),替换指定的类型参数,然后创建操作指定数据类型的方法的本地代码。CLR持续产生针对不同方法/数据类型组合的本地代码,这被称为代码爆炸。CLR有一些内建的优化器用以减少代码爆炸:首先,同一个AppDomain中不同的程序集均使用List<DateTime>, CLR仅会编译一次List<DateTime>。其次,CLR认为所有的引用类型都是等同的,因此,为使用List<String>参数的方法编译的代码,可以被使用List<Stream>参数的方法使用,因为所有引用类型参数事实上是指向位于堆上的对象的指针。所有针对指针的操作方法都一样。但是,如果类型参数是值类型,CLR必须为该值类型生成指定的本地代码,因为不同的CPU指令被用于操作这些值类型,即使他们有相同的大小(size)。委托事实上就是有如下四个方法的一个类定义:构造函数,Invoke方法,BeginInvoke方法和EndInvoke方法。
如果像下面这样定义了一个泛型委托:
public delegate TReturn CallMe(TKey key, TValue value);
编译器将其转换为类似于如下的一个类:
public sealed class CallMe{ public CallMe(Object obj, IntPtr method); public virtual TReturn Invoke(TKey key, TValue value); public virtual IAsyncResult BeginInvoke(TKey key, TValue value, AsyncCallback callback, Object obj); public virtual TReturn EndInvoke(IAsyncResult result);}
主限制(primary constraint) -- zero or one
引用类型(class): internal sealed class PrimaryConstraintOfClasswhere T : class{ public void M() { T temp = null;// Allowed because T must be a reference type }} 值类型(struct):internal sealed class PrimaryConstraintOfStruct where T : struct{ public static T Factory() { // Allowed because all value types implicitly // have a public, parameterless constructor return new T(); }}
辅助限制(secondary constraint) -- zero or more
接口类型限制以及嵌套类型限制
private static ListConvertIList (IList list) where T : TBase{ List baseList = new List (list.Count); for (Int32 index = 0; index < list.Count; index++) { baseList.Add(list[index]); } return baseList;}
构造函数限制(constructor constraint) -- zero or one
internal sealed class ConstructorConstraintwhere T : new(){ public static T Factory() { // Allowed because all value types implicitly // have a public, parameterless constructor and because // the constraint requires that any specified reference // type also have a public, parameterless constructor return new T(); }}
泛型类型和继承
internal sealed class Node{ public T m_data; public Node m_next; public Node(T data) : this(data, null){ } public Node(T data, Node next){ m_data = data; m_next = next; }} private static void SameDataLinkedList() { Node head = new Node ('C'); head = new Node ('B', head); head = new Node ('A', head); // 'A' 必须与'B'类型相同 Console.WriteLine(head.ToString()); }
更好的方法:
internal class Node{ protected Node m_next; public Node(Node next){ m_next = next; }}internal sealed class TypedNode: Node{ public T m_data; public TypedNode(T data) : this(data, null){ } public TypedNode(T data, Node next) : base(next){ m_data = data; }} private static void DifferentDataLinkedList(){ Node head = new TypedNode ('.'); head = new TypedNode (DateTime.Now, head); head = new TypedNode ("Today is ", head); // 'Today is' 可以与DateTime.Now类型不同 Console.WriteLine(head.ToString()); }