我试图从网上的几篇文章和 StackOverflow 上的问题中弄清楚这些词的确切含义,据Covariance
我Contravariance
所知,这只是polymorphism 的另一个词。
我对上述说法是否正确?还是我弄错了?
我试图从网上的几篇文章和 StackOverflow 上的问题中弄清楚这些词的确切含义,据Covariance
我Contravariance
所知,这只是polymorphism 的另一个词。
我对上述说法是否正确?还是我弄错了?
它肯定与多态性有关。我不会说它们只是多态性的“另一个词”——它们是关于非常具体的情况,在这种情况下,您可以将一种类型视为在特定上下文中的另一种类型。
例如,对于正常的多态性,您可以将任何对 aBanana
的引用视为对 a- 的引用,Fruit
但这并不意味着您可以在Fruit
每次看到 type 时进行替换Banana
。例如,List<Banana>
不能将 a 视为 a List<Fruit>
,因为list.Add(new Apple())
对 有效List<Fruit>
但对无效List<Banana>
。
协方差允许在 API 中替换“更大”(不太具体)的类型,其中原始类型仅用于“输出”位置(例如,作为返回值)。逆变允许在 API 中替换“更小”(更具体)的类型,其中原始类型仅用于“输入”位置。
很难在一篇 SO 帖子中详细介绍所有细节(尽管希望其他人会做得比这更好!)。Eric Lippert 有一系列关于它的优秀博客文章。
感谢所有的喊叫,伙计们。
Jon 和 Rasmus 的回答很好,我只想添加一个快速的技术说明。
是的,当随意和非正式地说话时,人们使用“协变”和“逆变”来指代一种特定的多态性。也就是说,您将一系列蜘蛛视为一系列动物的多态性。
如果我们获得所有计算机科学并尝试做出更多技术定义,那么我可能不会说协变和逆变是“一种多态性”。我会采用这样的技术定义:
首先,我注意到您可能会谈论 C# 中的两种可能的多态性,重要的是不要混淆它们。
第一种传统上称为“临时多态性”,这就是多态性,您有一个方法 M(Animal x),您将蜘蛛、长颈鹿和小袋鼠传递给它,并且该方法统一对待其传入的参数相同通过使用 Animal 基类保证的共性。
第二种传统上称为“参数多态性”,或“泛型多态性”。这就是创建一个泛型方法M<T>(T t)
然后在该方法中有一堆代码的能力,这些代码再次基于 T 上的约束所保证的共性来统一处理参数。
我认为您在谈论第一种多态性。但我的观点是,我们可以将多态性定义为一种编程语言基于已知共性统一处理不同事物的能力。(例如,已知的基本类型或已知的实现接口。)
协变和逆变是编程语言利用泛型类型之间从其类型参数的已知共性推导出的共性的能力。
您可以将协变和逆变视为多态的高级形式。您不仅可以像使用父类一样使用子类,而且具有协变和逆变,多态性扩展到与多态类相关的类。
想象两个类:
public class Pet { /*...*/ }
public class Cat:Pet { /*...*/ }
多态性能够使用 aCat
作为 a Pet
:
void Feed(Pet pet) { /* ... */ }
Cat cat = ...
Feed(cat);
协变和逆变用于谈论能够将 anICollection<Cat>
用作ICollection<Pet>
(协变):
void FeedAll(ICollection<Pet> pets) { /* ... */ }
List<Cat> cats = ...
FeedAll(cats);
或将 anAction<Pet>
用作Action<Cat>
(逆变):
Action<Pet> GetFeeder() { /* ... */ }
Action<Cat> feeder = GetFeeder();
Eric Lippert 在他们第一次设计该功能时写了一篇很棒的博客系列。第一部分在这里。
我找到了这个集合:
Covariance and Contravariance in C#, Part Ten: Dealing With Ambiguity
Covariance and Contravariance, Part Eleven: To infinity, but not beyond
我认为这是一种特殊的多态性,而不是另一个词。它是委托中的多态性,其中返回类型为 base 的委托可以接受子类型。