【问题标题】:C# : Is Variance (Covariance / Contravariance) another word for Polymorphism?C#:方差(协方差/逆变)是多态性的另一个词吗?
【发布时间】:2009-07-03 08:46:15
【问题描述】:

我试图从网上的几篇文章和 StackOverflow 上的问题中弄清楚 CovarianceContravariance 这两个词的确切含义,据我所知,这只是 多态性的另一个词.

我对上述说法是否正确?还是我弄错了?

【问题讨论】:

    标签: c# polymorphism covariance contravariance variance


    【解决方案1】:

    这当然与多态性有关。我不会说它们只是多态性的“另一个词”——它们是关于非常具体的情况,在这种情况下,您可以将一种类型视为另一种类型在特定上下文中

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

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

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

    【讨论】:

    • 啊,是的,事实上我正在阅读 Lippert 的帖子,发现它们很有帮助
    • 我认为这些博文都是在 2007 年 10 月发布的,所以它们可以在这个页面上找到:blogs.msdn.com/ericlippert/archive/2007/10.aspx
    • 不,最近该系列中还有一个(“虚无是不变的”)
    • Eric 在这方面的帖子很棒。我是否可以建议在答案中添加上述链接列表,因为他的博客软件无法处理这些标签。
    • 我会做更多的编辑来摆脱它不起作用的说法:)
    【解决方案2】:

    感谢所有的呼喊,伙计们。

    Jon 和 Rasmus 的回答很好,我只想添加一个简短的技术说明。

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

    如果我们获得所有计算机科学并尝试做出更多技术定义,那么我可能不会说协变和逆变是“一种多态性”。我会采用这样的技术定义:

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

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

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

    我想你说的是第一种多态性。但我的观点是,我们可以将多态性定义为编程语言根据已知的共性统一处理不同事物的能力。(例如,已知的基类型或已知的实现接口。)

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

    【讨论】:

    • 那么说 (co|contra)variance 是实现多态性的机制是否准确?
    • @EricLippert...所以您的意思是...它在通用级别是多态的,但在特定级别不是多态的;)我说只要Rain(T:Animal)就下雨猫狗
    【解决方案3】:

    您可以将协变和逆变视为多态的一种高级形式。您不仅可以像使用父类一样使用子类,还可以通过协变和逆变,将多态性扩展到与多态类相关的类。

    想象两个类:

    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&lt;Pet&gt; 作为Action&lt;Cat&gt;(逆变):

    Action<Pet> GetFeeder() { /* ... */ }
    
    Action<Cat> feeder = GetFeeder();
    

    Eric Lippert 在他们第一次设计该功能时写了一篇很棒的博客系列。第一部分是here

    【讨论】:

    • 在你的协方差例子中,不应该是void FeedAll(ICollection&lt;Pet&gt; pets)而不是ICollection&lt;Cat&gt;吗?
    • 我更喜欢你的帖子....更多颜色和代码示例。我喜欢漂亮的图片;)所以CoVariance是通过继承来评估的,ContraVariance是通过其他方式评估的……就像Contradictory一样?
    【解决方案4】:

    【讨论】:

    • 是的,这是 Lippert 的收藏
    【解决方案5】:

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

    【讨论】:

    • 不,这是函数参数和返回值的多态性方面。这意味着它会影响代表,但不需要它们
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-06
    • 1970-01-01
    • 2014-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多