协变和逆变
协变和逆变
约定:
A ≦ B
意味着 A 是 B 的子类型A → B
指的是以 A 为参数类型,以 B 为返回值类型的函数类型x : A
意味着 x 的类型为 A
协变和逆变的概念可以借助实际的变量类型来理解:
- 协变和普通变量:
在 C# 中,List
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;
这就是逆变。
参考: