一尘不染

协方差和反方差之间的差异

c#

我在理解协方差和反方差之间的区别时遇到了麻烦。


阅读 1147

收藏
2020-05-19

共1个答案

一尘不染

问题是“协方差和逆方差有什么区别?”

协方差和逆方差 是将集合的一个成员与另一个成员关联的映射函数的 属性。更具体地说,相对于该集合上的 关系 ,映射可以是协变的或相反的。

考虑所有C#类型集的以下两个子集。第一:

{ Animal, 
  Tiger, 
  Fruit, 
  Banana }.

其次,这个明显相关的集合:

{ IEnumerable<Animal>, 
  IEnumerable<Tiger>, 
  IEnumerable<Fruit>, 
  IEnumerable<Banana> }

从第一组到第二组有一个 映射 操作。即,对于第一集合中的每个T,第二集合中的 对应
类型为IEnumerable<T>。或者,简而言之,映射为T → IE<T>。请注意,这是一个“细箭头”。

到目前为止和我在一起?

现在让我们考虑一个 关系 。第一组类型对之间存在 分配兼容性关系
Tiger可以将type的值分配给type的变量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>

在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>已经 保留了存在,但反转的方向 分配的兼容性。也就是说,如果X ⇒ Y,则IC<X> ⇐ IC<Y>

其中A映射 蜜饯但反转 的关系被称为 逆变 映射。

同样,这显然是正确的。可以比较两个动物的设备也可以比较两个老虎,但是可以比较两个老虎的设备不一定可以比较任何两个动物。

因此,这就是C#4中协方差和相反方差的区别。协方差 保留 了可分配性的方向。逆差 反转

2020-05-19