zoukankan      html  css  js  c++  java
  • 协变与逆变

    转自:http://www.cnblogs.com/CLR010/p/3274310.html

    协变不是理所当然的,逆变也没有“逆”

    可以看到,从”实际流程图”来看,逆变根本没有“逆”,都离不开只能安全地把子类的引用赋给父类引用这个根本。

    来到这里应该基本理解逆变与协变了,不过装配脑袋的这篇文章有个更高级的问题,原文也有解答,这里我用上面画图的方式去理解它。

    图解逆变与协变的相互作用

    问题的提出,你知道那个正确吗?

    public interface IBar<in T> { }
    //应该是in
    public interface IFoo<in T>
    {
        void Test(IBar<T> bar);
    }
    //还是out
    public interface IFoo<out T>
    {
        void Test(IBar<T> bar);
    }

    答案是,如果是in的话,会编译失败,out才正确(当然不要泛型修饰符也能通过编译,但IFoo就没有协变能力了)。这里的意思就是说,一个有协 变(逆变)能力的泛型(IBar),作为另一个泛型(IFoo)的参数时,影响到了它(IFoo)的泛型的定义。乍一看以为是in的其中一个陷阱是T是在 Test方法的参数里的,所以以为是in。但这里Test的参数根本不是T,而是IBar<T>。

    我们画个图来理解它。既然out可以通过,那么它的“协变流程图”应该如下:

      图跟前面那些大致一样,但理解它要跟问题相反(上面问题是先定义好IBar,再去定义IFoo)。1.我们定义好一个有协变能力的IFoo,这是前 提。2.可以推出,上面的流程是成立的。3.这个流程重点是参数流向,要使整个流程成立,就必须使IBar<string> = IBar<object>成立,这不就是逆变吗?整个结论就是,有协变能力的IFoo要求它的泛型参数(IBar)有逆变能力。其实根据上面的箭头也可以理解,因为原式和变式的变向跟参数的变向是相反的,导致了它们要有相反的能力,这就是装配脑袋文章说的:方法参数的协变-反变互换原则。根据这个原理,也很容易得出,如果Test方法的返回值是IBar<T>,而不是参数,那么就要求IBar<T>要有协变能力,因为返回值的箭头与原式和变式的变向的箭头是同向的。

  • 相关阅读:
    Android学习第一课
    窗体 dialog 弹出时动画效果
    poj2105 IP Address(简单题)
    #定位系统性能瓶颈# strace &amp; ltrace
    POJ2142——The Balance
    排序算法系列之八大排序算法性能比較-从实验结果分析
    DuFile网赚网盘
    一次dns缓存引发的惨案
    IT大咖说
    HTTPS与SNI扩展,一个IP绑定多个SSL证书 | VeriSign|SSL证书|数字签名证书|服务器证书|微软代码签名证书|Symantec
  • 原文地址:https://www.cnblogs.com/xinzheng/p/5730672.html
Copyright © 2011-2022 走看看