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<TReturn, TKey, TValue>(TKey key, TValue value);
编译器将其转换为类似于如下的一个类:
public sealed class CallMe<TReturn, TKey, TValue> { 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 PrimaryConstraintOfClass<T> where T : class { public void M() { T temp = null;// Allowed because T must be a reference type } }
值类型(struct): internal sealed class PrimaryConstraintOfStruct<T> 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 List<TBase> ConvertIList<T, TBase>(IList<T> list) where T : TBase { List<TBase> baseList = new List<TBase>(list.Count); for (Int32 index = 0; index < list.Count; index++) { baseList.Add(list[index]); } return baseList; }
构造函数限制(constructor constraint) -- zero or one
internal sealed class ConstructorConstraint<T> where 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<T> { public T m_data; public Node<T> m_next; public Node(T data) : this(data, null){ } public Node(T data, Node<T> next){ m_data = data; m_next = next; } }
private static void SameDataLinkedList()
{
Node<Char> head = new Node<Char>('C');
head = new Node<Char>('B', head);
head = new Node<Char>('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<T> : 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<Char>('.');
head = new TypedNode<DateTime>(DateTime.Now, head);
head = new TypedNode<String>("Today is ", head); // 'Today is' 可以与DateTime.Now类型不同
Console.WriteLine(head.ToString());
}