协变与逆变的概念


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

简单的举个例子:

List<string> str;
List<Object> obj;

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

我们可以简单理解为:

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

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

关于in和out修饰符


下面用到的三个类: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百科——协变与逆变、各种博客。

[C#]关于逆变与协变的基本概念和修饰符in与out的意义的更多相关文章

  1. Java中的逆变与协变

    看下面一段代码 Number num = new Integer(1); ArrayList<Number> list = new ArrayList<Integer>(); ...

  2. scala 学习: 逆变和协变

    scala 逆变和协变的概念网上有很多解释, 总结一句话就是 参数是逆变的或者不变的,返回值是协变的或者不变的. 但是为什么是这样的? 协变: 当s 是A的子类, 那么func(s) 是func(A) ...

  3. Scala 深入浅出实战经典 第81讲:Scala中List的构造是的类型约束逆变、协变、下界详解

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-97讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  4. C#4.0新特性(3):变性 Variance(逆变与协变)

    一句话总结:协变让一个粗粒度接口(或委托)可以接收一个更加具体的接口(或委托)作为参数(或返回值):逆变让一个接口(或委托)的参数类型(或返回值)类型更加具体化,也就是参数类型更强,更明确. 通常,协 ...

  5. Java中的逆变与协变(转)

    看下面一段代码 Number num = new Integer(1); ArrayList<Number> list = new ArrayList<Integer>(); ...

  6. Java 逆变与协变的名词说明

    最近在研究Thinking in Java的时候,感觉逆变与协变有点绕,特意整理一下,方便后人.我参考于Java中的逆变与协变,但是该作者整理的稍微有点过于概念化,我在这里简单的说一下 我对于协变于逆 ...

  7. C# 逆变与协变

    该文章中使用了较多的 委托delegate和Lambda表达式,如果你并不熟悉这些,请查看我的文章<委托与匿名委托>.<匿名委托与Lambda表达式>以便帮你建立完整的知识体系 ...

  8. Java 逆变与协变

    最近一直忙于学习模电.数电,搞得头晕脑胀,难得今天晚上挤出一些时间来分析一下Java中的逆变.协变.Java早于C#引入逆变.协变,两者在与C#稍有不同,Java中的逆变.协变引入早于C#,故在形式没 ...

  9. .NET 4.0中的泛型逆变和协变

    转载自:http://www.cnblogs.com/Ninputer/archive/2008/11/22/generic_covariant.html:自己加了一些理解 随Visual Studi ...

  10. .NET:为什么需要逆变和协变

    为啥需要协变和逆变? 我目前想到的理由是:逆变和协变的目的是支持多态. 一个小例子 不明白为啥输出的是false和true. using System; using System.Collection ...

随机推荐

  1. Linux基础_4_文件夹管理

    文件路径 . #表示当前目录,同./ .. #表示上级目录,同../ ../../ #表示上上级目录 / #表示根目录 注:文件名长度不超过255个字符 注:.开头为隐藏文件 切换目录 cd #默认切 ...

  2. 『现学现忘』Git分支 — 40、分支基本操作(一)

    目录 1.创建分支 (1)创建分支 (2)图示理解 2.查看分支列表 3.分支切换 4.查看所有分支的最后一个提交 5.删除分支 1.创建分支 (1)创建分支 Git 是怎么创建新分支的呢? 很简单, ...

  3. 5.-GET请求和POST请求

    一.定义 无论是GET请求还是POST,统一由视图函数接收请求,通过判定request.method区分具体的请求动作     二.GET处理 GET请求方式中,如果有数据需要传递给服务器,通常会用查 ...

  4. 重新整理 .net core 实践篇 ———— linux上排查问题实用工具 [外篇]

    前言 介绍下面几个工具: Lldb createdump dotnet-dump dotnet-gcdump dotnet-symbol Procdump 该文的前置篇为: https://www.c ...

  5. day11-Servlet01

    Servlet01 官方api文档:https://tomcat.apache.org/tomcat-8.0-doc/servletapi/index.html Servlet和Tomcat的关系:一 ...

  6. STF的DOCKER搭建

    OPENSTF OpenSTF(Smartphone Test Farm)是一个web端移动设备管理平台,可以从浏览器端远程调试.远程管理设备.其实有点类似于我们现在很火热的云测平台,如:testin ...

  7. 小程序利用canvas 绘制图案 (生成海报, 生成有特色的头像)

    小程序利用canvas 绘制图案 (生成海报, 生成有特色的头像) 微信小程序生成特色头像,海报等是比较常见的.下面我来介绍下实现该类小程序的过程. 首先选择前端来通过 canvas 绘制.这样比较节 ...

  8. JVM运行时数据区域详解

    参考文章: <Java Se11 虚拟机规范> <深入理解Java虚拟机-JVM高级特性与最佳实践 第3版>- 周志明 本文基于Java Se 11讲解. 根据<Java ...

  9. idea中springboot热部署(无需重启项目)

    idea中springboot热部署(无需重启项目) 1.在pom.xml文件中导入依赖 <dependency> <groupId>org.springframework.b ...

  10. 微信小程序经纬度转化为具体位置(逆地址解析)

    小程序wx.getLocation只能获取经纬度, 这时候想要具体地址就需要借助第三方sdk(逆地址解析) 我这边第三方以腾讯位置服务举例 一. 首先小程序需要申请wx.getLocation接口权限 ...