协变(Covariance)
使你能够使用比原始指定的类型派生程度更大的类型。
你可以将 IEnumerable<Derived> 的实例分配给 IEnumerable<Base> 类型的变量。
简单理解:把细的赋给粗的,适用于赋值。
示例
public class Base { } public class Derived : Base { } IEnumerable<Derived> d = new List<Derived>(); IEnumerable<Base> b = d;
可以看出,很像多态嘛。
以上在 .NET Framework 3.5 中是报错的,但是在 4.6.2,它不会报错。
逆变(Contravariance)
使你能够使用比原始指定的类型更泛型(派生程度更小)的类型。
你可以将 Action<Base> 的实例分配给 Action<Derived> 类型的变量。
简单理解:把粗的赋给细的,适用于赋形参。
// 如下是不行的。 IEnumerable<Base> d = new List<Base>(); IEnumerable<Derived> b = d; // 这里会报错。 // 但是作为参数是可以的。 Action<Base> b = (p) => { }; Action<Derived> d = b; // 正常。
之所有可以把粗的赋给细的,是因为这是形参,不是实在的对象。
有什么用?
除了理解编程原理,意义真不大,如果意义大,经常用到,大家就很熟悉了。
Action<Base> b = (p) => { }; Action<Derived> d = b; b(new Derived()); b(new Base()); d(new Derived()); d(new Base()); // 错误。
如上代码 b 这个方法,传 Derived、Base 对象都可以,但是我某处应用就不希望传 Base 对象,于是 Action<Derived> d = b;(逆变),d 就不能用 Base 对象了。
相关阅读
泛型中的协变和逆变 | Microsoft Docs
C# 中 Action 和 Func