委托的每个泛型类型参数都可以标记为协变量或逆变量。(协变性指定返回类型的兼容性,而逆变性指定参数的兼容性)利用这个功能,可将泛型委托类型的变量转换为相同的委托类型(但泛型参数类型不同)。泛型类型参数可以是以下任何一种形式。
1.不变量(invariant) 意味着泛型类型参数不能改变。
2.逆变量(contravariant)意味着泛型类型参数可以从一个类更改为它的某个派生类。在C#是用in关键字标记逆变量形式的泛型参数。逆变量泛型类型参数只出现在输入位置,比如作为方法的参数。
3.协变量(covariant)意味着泛型类型参数可以从一个类更改为它的某个基类。C#是用out关键字标记协变量形式的泛型类型参数。协变量泛型类型参数只能出现在输出位置,比如作为方法的返回类型。
例如:
其中,泛型类型参数T用in关键字标记,这使它成为逆变量;泛型类型参数TResult用out关键字标记,这使它成为协变量。
所以,像下面这样:
fn1变量引用一个方法,获取一个object,返回一个ArgumentException。而fn2变量引用另一个方法,获取一个string返回一个Exception。由于可将一个string传给期待object的方法(因为string从object派生),而且由于可以获取返回ArgumentException的一个方法的结果,并将这个结果当成一个Exception(因为Exception是ArgumentException的基类),所以上述代码正常编译,而编译时能维持类型安全性。
//--
只有编译器能验证类型之间存在引用转换,这些可变性才有用。换言之,由于需要装箱,所以值类型不具有这种可变性。
//--
使用要获取泛型参数和返回值的委托时,建议尽量为逆变性和协变性指定in和out关键字。这样做不会有不良反应,并使你的委托能在更多的情形中使用。
//--
和委托相似,具有泛型类型参数的接口也可以将雷星星参数标记为逆变量和协变量。