zoukankan      html  css  js  c++  java
  • 转载 协变与逆变的概念

    https://www.cnblogs.com/lizhenghao126/p/11053666.html

     

    假如两个类型XY具有特殊关系,X类型的每个值都能转换成Y类型。我们将I<X>I<Y>的转换称为协变转换。反之我们将I<Y>I<X>的转换称为逆变转换。

    简单的举个例子:

    List<string> str;

    List<Object> obj;

    我们知道在C#中所有引用类型都直接或间接地继承自Object类,所有string都可以转换成Object类,因此将str转换成obj是协变转换,反之则为逆变转换。

    我们可以简单理解为:

    • 由派生类向基类方向转变是协变
    • 由基向派生类方向转变是逆变

       

    关于inout修饰符

    下面用到的三个类:Animal类、Dog类、Cat类。

    • 协变:一个Cat[]也是Animal[]
    • 逆变:一个Animal[]也是Cat[] 

      如果要避免类型错误,并且支持读写操作,那么只有第三种情况是安全的(不允许进行类型转换),
      Animal[]并不是总能当作Cat[],因为当一个客户读取数组并期望得到一个Cat,但Animal[]中包含的可能是个Dog。所以逆变规则是不安全的。 

      反之,一个Cat[]也不能被当作一个Animal[]。因为总是可以把一个Dog放到Animal[]中。在协变数组,这就不能保证是安全的,因为背后的存储可以实际是Cat[]。因此协变规则也不是安全的

      但是,只读数据类型是协变的(也就是说只需要数据只读,那么协变就是安全的),只写数据类型是逆变的(只需要数据只写,那么逆变就是安全的)

    这时候我们的in修饰符和out修饰符就派上用场了:

    • C#4.0中使用out类型参数修饰符允许协变性,它会导致编译器验证该类型是否真的只作用于"输出",即只用于方法的返回类型和只读属性的返回类型,永远不用于形参或者属性的赋值方法,如果验证通过则编译器会允许协变操作。
    • C#4.0中使用in类型参数修饰符允许逆变性,它只是编译器核实类型从未在属性的取值方法(get访问器)中出现,也没有作为方法的返回类型使用,如果检查无误则会允许逆变操作。

    关于协变转换的额一些限制

    1. 只有泛型接口和泛型委托才可以是协变的。泛型类和结构永远不是协变的。
    2. 协变的来源和目标必须是引用类型不能是值类型,也就是说不能一个是object,另一个是int
    3. 接口或委托必须声明为支持协变,编译器必须验证协变所针对的类型参数确实只用在"输出"的位置。 

      参考:《C#6.0本质论》、wiki百科——协变与逆变、各种博客。

      https://github.com/li-zheng-hao

  • 相关阅读:
    svn 常用控制台命令解析
    android studio Activity标题栏研究
    android 音频播放总结 soundlPool,MediaPlay
    android studio 将library导出为jar 亲测成功
    android 控件自定义样式
    android studio 程序错误
    android 界面布局
    jdk 多版本安装 for mac
    android 控件ui
    homebrew for mac
  • 原文地址:https://www.cnblogs.com/ifconfig/p/13167527.html
Copyright © 2011-2022 走看看