问题是“协变和逆变有什么区别?”
协变和逆变是将集合中的一个成员与另一个成员关联起来的映射函数。更具体地说,映射可以是协变的或逆变的relation在那一套上。
考虑所有 C# 类型集的以下两个子集。第一的:
{ Animal,
Tiger,
Fruit,
Banana }.
其次,这个明显相关的集合:
{ IEnumerable<Animal>,
IEnumerable<Tiger>,
IEnumerable<Fruit>,
IEnumerable<Banana> }
有一个mapping从第一组操作到第二组。也就是说,对于第一组中的每个 T,相应的第二组的类型是IEnumerable<T>
。或者,简单来说,映射是T → IE<T>
。请注意,这是一个“细箭头”。
到目前为止和我在一起吗?
现在让我们考虑一个relation。有一个赋值相容关系在第一组中的类型对之间。类型的值Tiger
可以分配给类型的变量Animal
,因此这些类型被称为“赋值兼容”。让我们写“一个类型的值X
可以分配给类型的变量Y
“ 更短的形式:X ⇒ Y
。请注意,这是一个“粗箭头”。
因此,在我们的第一个子集中,以下是所有分配兼容性关系:
Tiger ⇒ Tiger
Tiger ⇒ Animal
Animal ⇒ Animal
Banana ⇒ Banana
Banana ⇒ Fruit
Fruit ⇒ Fruit
在支持某些接口的协变赋值兼容性的 C# 4 中,第二组中的类型对之间存在赋值兼容性关系:
IE<Tiger> ⇒ IE<Tiger>
IE<Tiger> ⇒ IE<Animal>
IE<Animal> ⇒ IE<Animal>
IE<Banana> ⇒ IE<Banana>
IE<Banana> ⇒ IE<Fruit>
IE<Fruit> ⇒ IE<Fruit>
请注意,映射T → IE<T>
保留赋值兼容性的存在和方向。也就是说,如果X ⇒ Y
,那么也成立IE<X> ⇒ IE<Y>
.
如果粗箭头的两侧都有两个东西,那么我们可以用相应的细箭头右侧的东西替换两侧。
对于特定关系具有此属性的映射称为“协变映射”。这应该是有道理的:在需要动物序列的地方可以使用老虎序列,但反之则不然。在需要老虎序列的地方不一定使用动物序列。
这就是协方差。现在考虑所有类型集合的这个子集:
{ IComparable<Tiger>,
IComparable<Animal>,
IComparable<Fruit>,
IComparable<Banana> }
现在我们有了从第一组到第三组的映射T → IC<T>
.
In C# 4:
IC<Tiger> ⇒ IC<Tiger>
IC<Animal> ⇒ IC<Tiger> Backwards!
IC<Animal> ⇒ IC<Animal>
IC<Banana> ⇒ IC<Banana>
IC<Fruit> ⇒ IC<Banana> Backwards!
IC<Fruit> ⇒ IC<Fruit>
也就是说,映射T → IC<T>
has 保留了存在但颠倒了方向分配兼容性。也就是说,如果X ⇒ Y
, then IC<X> ⇐ IC<Y>
.
一个映射其中保留但反转关系称为逆变映射。
再次强调,这应该是明显正确的。可以比较两只动物的设备也可以比较两只老虎,但是可以比较两只老虎的设备不一定可以比较任何两只动物。
这就是 C# 中协变和逆变的区别 4. 协变果酱可分配性的方向。逆变reverses it.