约定:
A ≦ B
意味着 A 是 B 的子类型A → B
指的是以 A 为参数类型,以 B 为返回值类型的函数类型x : A
意味着 x 的类型为 A
协变和逆变的概念可以借助实际的变量类型来理解:
- 协变和普通变量
-
在 C# 中,List<T> 类实现 IEnumerable<T> 接口,因此 List<Derived> 实现 IEnumerable<Derived>:
IEnumerable<Derived> d = new List<Derived>(); IEnumerable<Base> b = d;
简单来说,协变就和面向对象概念中的多态一样,指可以使用父类型引用指向子类型实例的情况。
- 逆变和函数变量
-
假如我有这样一个类型链:C ≦ B ≦ A,此时有一个函数是这样的:f(B → B),这个函数接收一个 B → B 函数作为参数, 那么这种情况下,怎样的函数可以作为 f 的参数呢?
首先,对于
C → *
来说都是不行的,因为 f 调用函数时参数类型可能是 B 或 B 的其他子类型,而C → *
只支持 C 类型的入参。然后,对于
* → A
来说也是不行的,因为 f 要求的返回值是 B 或 B 的其他子类型,但是* → A
可能会返回 B 的父类型 A。最后,对于
A → C
来说却是可行的,因为 f 的参数只会是 B 或 B 的其他子类型,而A → C
的入参类型是 A,满足。 同时,函数A → C
的返回值是 C,是 B 的子类型,返回值类型也满足。这时,神奇的情况便发生了,当函数类型是
B → B
时,我们可以使用<? super B> → <? extend B>
进行赋值:Action<Base> b = (target) => { Console.WriteLine(target.GetType().Name); }; Action<Derived> d = b;
这就是逆变。
参考: