C#:方差(协方差/反variables)是多态吗?
我想从网上的几篇文章和StackOverflow上的问题中Contravariance
Covariance
和“ Contravariance
”一词的确切含义,从我能理解的情况来看,这只是多态的另一个词 。
我是否正确的以上陈述? 还是我错了?
这当然与多态性有关。 我不会说它们只是多态的“另一个单词” – 它们是关于非常特定的情况,在这种情况下,可以将某种types看作是某种上下文中的另一种types。
例如,对于正常的多态性,您可以将任何对Banana
的引用视为对Fruit
的引用 – 但这并不意味着您每次看到Banana
types都可以replaceFruit
。 例如, List<Banana>
不能被当作List<Fruit>
处理,因为list.Add(new Apple())
对List<Fruit>
有效,对于List<Banana>
不可用。
协方差允许在原始types仅用于“输出”位置(例如作为返回值)的API中用“较大”(较不具体的)types替代。 反变换允许在原始types仅用于“input”位置的API中replace“更小”(更具体)的types。
在一篇SOpost中很难详细讨论所有细节(尽pipe希望别人能做得比这更好)。 Eric Lippert有一个很好的博客文章系列 。
感谢所有的喊声,伙计。
乔恩和拉斯穆斯的答案都很好,我只是添加一个快速的技术说明。
当随便和非正式的发言,是的,人们使用“协变”和“反转”来指代一种特定的多态。 也就是说,你把一系列蜘蛛看作是一系列动物的多态性。
如果我们要得到所有的计算机能力,并试图做出更多的技术定义,那么我可能不会说协变和逆变是“一种多态”。 我会接近这样一个更技术性的定义:
首先,我会注意到C#中可能存在两种可能的多态,你可能会说,不要混淆它们。
第一种传统上被称为“ad hoc多态性”,这就是你有一个方法M(Animal x)的多态性,并且把蜘蛛,长颈鹿和小袋鼠传递给它,并且方法统一的将它的传入参数通过使用动物基类保证的共同点。
第二类传统上被称为“参数多态”,或“generics多态”。 这就是能够生成一个通用方法M<T>(T t)
,然后在方法中有一堆代码,再次根据T上约束保证的共同性来处理参数。
我想你在谈论第一种多态。 但我的观点是,我们可以将多态性定义为编程语言根据已知的通用性统一处理不同事物的能力。 (例如,已知的基本types或已知的实现的接口。)
协变和逆变是编程语言利用从它们types参数的已知共性推导出的generics之间的共同性的能力。
你可以把共同和反变换看成多态的高级forms。 您不仅可以像使用父类一样使用子类,而且还可以使用协变和变换,多态扩展到与多态类相关的类。
设想两个类:
public class Pet { /*...*/ } public class Cat:Pet { /*...*/ }
多态是能够使用Cat
作为Pet
:
void Feed(Pet pet) { /* ... */ } Cat cat = ... Feed(cat);
协变和反variables用于讨论能够使用ICollection<Cat>
作为ICollection<Pet>
(协方差):
void FeedAll(ICollection<Pet> pets) { /* ... */ } List<Cat> cats = ... FeedAll(cats);
或将Action<Pet>
用作Action<Cat>
(逆变):
Action<Pet> GetFeeder() { /* ... */ } Action<Cat> feeder = GetFeeder();
Eric Lippert在第一次devise这个function时写了一个很棒的博客系列。 第一部分在这里 。
我发现这个集合:
C#中的协变与逆变,第一部分
C#协方差与协变性,第二部分:数组协方差
C#中的协方差与反变换,第三部分:成员组转换方差
C#中的协变与逆变,第四部分:实际代表差异
C#中的协方差和反variables,第五部分:高阶函数伤害了我的大脑
C#中的协方差和反变换,第六部分:接口方差
C#中的协变与逆变第七部分:为什么我们需要一个语法?
C#中的协方差与反变换,第八部分:语法选项
C#中的协变与逆变,第九部分:突破性变化
C#中的协变与逆变,第十部分:处理歧义
协变与逆变,第十一部分:无限,但不能超越
我认为是一种特殊的多态现象,而不是另一种说法。 在委托中 ,具有基类返回types的委托可以接受子types是多态的。