我在理解协方差和反方差之间的区别时遇到了麻烦。
问题是“协方差和逆方差有什么区别?”
协方差和逆方差 是将集合的一个成员与另一个成员关联的映射函数的 属性。更具体地说,相对于该集合上的 关系 ,映射可以是协变的或相反的。
考虑所有C#类型集的以下两个子集。第一:
{ Animal, Tiger, Fruit, Banana }.
其次,这个明显相关的集合:
{ IEnumerable<Animal>, IEnumerable<Tiger>, IEnumerable<Fruit>, IEnumerable<Banana> }
从第一组到第二组有一个 映射 操作。即,对于第一集合中的每个T,第二集合中的 对应 类型为IEnumerable<T>。或者,简而言之,映射为T → IE<T>。请注意,这是一个“细箭头”。
IEnumerable<T>
T → IE<T>
到目前为止和我在一起?
现在让我们考虑一个 关系 。第一组类型对之间存在 分配兼容性关系 。Tiger可以将type的值分配给type的变量Animal,因此这些类型被称为“分配兼容”。让我们以较短的形式编写“ X可以将类型的值分配给类型的变量Y”:X ⇒ Y。请注意,这是一个“胖箭头”。
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>。
IE<X> ⇒ IE<Y>
如果在粗箭头的两侧都有两个东西,则可以用相应的细箭头右侧的东西替换两侧。
相对于特定关系具有此属性的映射称为“协变量映射”。这应该是有道理的:在需要一系列动物的情况下,可以使用一系列老虎,但事实并非如此。需要老虎序列时,不一定必须使用动物序列。
那是协方差。现在考虑所有类型集合的这个子集:
{ IComparable<Tiger>, IComparable<Animal>, IComparable<Fruit>, IComparable<Banana> }
现在我们有了从第一组到第三组的映射T → IC<T>。
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>。
IC<X> ⇐ IC<Y>
其中A映射 蜜饯但反转 的关系被称为 逆变 映射。
同样,这显然是正确的。可以比较两个动物的设备也可以比较两个老虎,但是可以比较两个老虎的设备不一定可以比较任何两个动物。
因此,这就是C#4中协方差和相反方差的区别。协方差 保留 了可分配性的方向。逆差 将 其 反转 。