C#:方差(协方差/反解)是多态性的另一个词吗?

时间:2009-07-03 08:46:15

标签: c# polymorphism covariance contravariance variance

我试图从网上的几篇文章和StackOverflow上的问题中找出单词CovarianceContravariance的确切含义,并且根据我的理解,它只是的另一个词多态性

我对上述陈述是否正确?或者我弄错了?

5 个答案:

答案 0 :(得分:66)

这肯定与多态性有关。我不会说它们只是多态性的“另一个词” - 它们是关于非常具体的情况,你可以将一种类型视为某种上下文中的另一种类型 。 / p>

例如,对于普通的多态性,您可以将对Banana的任何引用视为对Fruit的引用 - 但这并不意味着您可以替换每个Fruit 您看到类型Banana的时间。例如,List<Banana>不能视为List<Fruit>,因为list.Add(new Apple())List<Fruit>有效,但对List<Banana>无效。

协方差允许在API中替换“更大”(更不具体)类型,其中原始类型仅 在“输出”位置使用(例如,作为返回值)。 Contravariance允许在API中替换“较小”(更具体)类型,其中原始类型仅 在“输入”位置使用。

很难在单个SO帖子中详细介绍所有细节(尽管希望其他人能做得比这更好!)。 Eric Lippert对此有一个很好的series of blog posts

答案 1 :(得分:44)

感谢所有人的支持。

Jon和Rasmus的答案很好,我只想添加一个快速的技术说明。

当随便和非正式地说话时,是的,人们使用“协方差”和“逆变”来指代特定类型的多态性。也就是说,你将一系列蜘蛛视为一系列动物的多态性。

如果我们要获得所有计算机技术并尝试制定更多技术定义,那么我可能不会说协方差和逆变是“一种多态”。我会接近这样一个更技术性的定义:

首先,我注意到你可能正在谈论的C#中有两种可能的多态性,重要的是不要混淆它们。

第一种传统上称为“ad hoc多态性”,这是多态,你有一个方法M(动物x),你传递蜘蛛,长颈鹿和小袋鼠,并且该方法统一处理它的传入通过使用Animal基类保证的共性,以相同的方式进行参数化。

第二种传统上称为“参数多态”或“通用多态”。这是制作泛型方法M<T>(T t)的能力,然后在方法中有一堆代码,再次根据T上的约束保证的共性来统一处理参数。

我认为你在谈论第一种多态性。但我的观点是,我们可以将多态定义为编程语言基于已知的通用性统一处理不同事物的能力。(例如,已知的基本类型或已知的已实现接口。)

协方差和逆变是指编程语言能够利用从类型参数的已知共性推导出的泛型类型之间的共性。

答案 2 :(得分:18)

您可以将共同和逆变视为多态的高级形式。您不仅可以使用子类,就像它的父类一样,具有共同和逆变,多态性扩展到与多态类相关的类。

想象一下两个类:

public class Pet { /*...*/ }
public class Cat:Pet { /*...*/ }

多态性能够将Cat用作Pet

void Feed(Pet pet) { /* ... */ }

Cat cat = ...
Feed(cat);

使用协变量和逆变量来讨论能够使用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在他们第一次设计这个功能时写了一篇很棒的博客系列。第一部分是here

答案 3 :(得分:13)

答案 4 :(得分:-2)

我认为是一种特殊的多态,而不是另一个词。它是委托中的多态,其中返回类型为base的委托可以接受子类型。