封闭类型才能创建实例,开放类型不能创建实例;
每个封闭类型都有自己的静态字段;
通过泛型实现一个链表:
//链表基类
internal class Node
{
protected Node m_next;
public Node(Node next)
{
this.m_next = next;
}
}
//链表派生类
internal class NodeType<T>: Node
{
public T m_data;
public NodeType(T data): this(data, null)
{
}
public NodeType(T data, Node next) : base(next)
{
this.m_data = data;
}
public override string ToString()
{
return this.m_data.ToString() + ((this.m_next != null) ? this.m_next.ToString() : String.Empty);
}
}
委托和接口泛型中的逆变和协变
不变量: 意味着泛型类型参数不能更改。
逆变量: 意味着泛型类型参数可以从一个类更改为它的某个派生类。在C#是用in关键字标记逆变量形式的泛型类型参数。逆变量泛型类型参数只出现在输入位置,比如作为方法的参数。
协变量: 意味着泛型类型参数可以从一个类更改为它的某个基类。C#是用out关键字标记协变量形式的泛型类型参数。协变量泛型类型参数只能出现在输出位置,比如作为方法的返回类型。
例如:
Func<Object, ArgumentException> fn1 = null;
Func<string, Exception> fn2 = fn1;
是能够成立的。因为fn1变量引用一个方法,获取一个Object,返回一个ArgumentException。而fn2变量引用另一个方法,获取一个String,返回一个Exception。由于可将一个String传给期待Object的方法(因为String从Object派生),而且由于可以获取返回ArgumentException的一个方法的结构,并将这个结构当成一个Exception(因为Exception 是 ArgumentException 的基类),所以上述代码能正常编译。
可验证性和约束
private static T Min<T>(T o1, T o2) where T : IComparable<T>
{
if (o1.CompareTo(o2) < 0)
{
return o1;
}
return o2;
}
where关键字告诉编译器,为T指定的任何类型都必须实现同类型(T)的泛型IComparable<T>接口。
约束可用于泛型类型的类型参数,也可应用于泛型方法的类型参数。(注: CLR不允许基于类型参数名称或约束来进行重载; 只能基于类型参数个数对类型或方法进行重载)
重写虚泛型方法时,重写的方法必须指定相同数量的类型参数,而且这些类型参数会继承在基类方法上指定的约束。事实上,根本不允许为重写方法的类型参数指定任何约束。但是类型参数的名称是可以改变的。 实现接口方法时类似。
主要约束
类型参数可以指定零个或一个主要约束。主要约束可以是代表非密封类的一个引用类型。(不能指定以下特殊引用类型: System.Object, System.Array, System.Delegate, System.MulticastDelegate, System.ValueType, System,Enum 或者 System.Void)。
指定引用类型约束时,相当于向编译器承诺: 一个指定的类型实参要么是与约束类型相同的类型,要么是从约束类型派生的类型。
次要约束
类型参数可以指定零个或多个次要约束,次要约束代表接口类型。这种约束向编译器承诺类型实参实现了接口。
还有一种次要约束称为类型参数约束,有时也称为裸类型约束。它允许一个泛型类型或方法规定: 指定的类型实参要么就是约束的类型,要么是约束的类型的派生类。如下:
private static List<TBase> ConvertIList<T, TBase>(IList<T> list) where T: TBase
{
List<TBase> baseList = new List<TBase>(list.Count);
for (int index = 0; index < list.Count; index++)
{
baseList.Add(list[index]);
}
return baseList;
}
构造器约束
类型参数可指定零个或一个构造器约束, 它向编译器承诺类型实参是实现了公共无参构造器的非抽象类型。(注: 如果同时使用构造器约束和struct约束,C#编译器会认为这是一个错误,因为这是多余的。)
internal class ConstructorConstraint<T> where T : new()
{
public static T Factory()
{
//允许,因为所有值类型都隐式有一个公共无参构造器。
//如果指定的是引用类型,约束也要求它提供公共无参构造器
return new T();
}
}