[C#]关于逆变与协变的基本概念和修饰符in与out的意义
协变与逆变的概念
假如两个类型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访问器)中出现,也没有作为方法的返回类型使用,如果检查无误则会允许逆变操作。
关于协变转换的额一些限制
- 只有泛型接口和泛型委托才可以是协变的。泛型类和结构永远不是协变的。
- 协变的来源和目标必须是引用类型不能是值类型,也就是说不能一个是object,另一个是int。
接口或委托必须声明为支持协变,编译器必须验证协变所针对的类型参数确实只用在“输出”的位置。
参考:《C#6.0本质论》、wiki百科——协变与逆变、各种博客。
[C#]关于逆变与协变的基本概念和修饰符in与out的意义的更多相关文章
- Java中的逆变与协变
看下面一段代码 Number num = new Integer(1); ArrayList<Number> list = new ArrayList<Integer>(); ...
- scala 学习: 逆变和协变
scala 逆变和协变的概念网上有很多解释, 总结一句话就是 参数是逆变的或者不变的,返回值是协变的或者不变的. 但是为什么是这样的? 协变: 当s 是A的子类, 那么func(s) 是func(A) ...
- Scala 深入浅出实战经典 第81讲:Scala中List的构造是的类型约束逆变、协变、下界详解
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-97讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...
- C#4.0新特性(3):变性 Variance(逆变与协变)
一句话总结:协变让一个粗粒度接口(或委托)可以接收一个更加具体的接口(或委托)作为参数(或返回值):逆变让一个接口(或委托)的参数类型(或返回值)类型更加具体化,也就是参数类型更强,更明确. 通常,协 ...
- Java中的逆变与协变(转)
看下面一段代码 Number num = new Integer(1); ArrayList<Number> list = new ArrayList<Integer>(); ...
- Java 逆变与协变的名词说明
最近在研究Thinking in Java的时候,感觉逆变与协变有点绕,特意整理一下,方便后人.我参考于Java中的逆变与协变,但是该作者整理的稍微有点过于概念化,我在这里简单的说一下 我对于协变于逆 ...
- C# 逆变与协变
该文章中使用了较多的 委托delegate和Lambda表达式,如果你并不熟悉这些,请查看我的文章<委托与匿名委托>.<匿名委托与Lambda表达式>以便帮你建立完整的知识体系 ...
- Java 逆变与协变
最近一直忙于学习模电.数电,搞得头晕脑胀,难得今天晚上挤出一些时间来分析一下Java中的逆变.协变.Java早于C#引入逆变.协变,两者在与C#稍有不同,Java中的逆变.协变引入早于C#,故在形式没 ...
- .NET 4.0中的泛型逆变和协变
转载自:http://www.cnblogs.com/Ninputer/archive/2008/11/22/generic_covariant.html:自己加了一些理解 随Visual Studi ...
- .NET:为什么需要逆变和协变
为啥需要协变和逆变? 我目前想到的理由是:逆变和协变的目的是支持多态. 一个小例子 不明白为啥输出的是false和true. using System; using System.Collection ...
随机推荐
- 10.pygame-碰撞检测
添加并监听英雄发射子弹事件 class Hero(GameSprite): def __init__(self): # 调用父类方法,设置image super().__init__('./image ...
- DQL语句排序与分组
DQL语句排序与分组 一.DQL-排序 排序是计算机内经常进行的一种操作,其目的是将一组"无序"的记录序列调整为"有序"的记录序列.分内部排序和外部排序,若整个 ...
- 如何免安装使用 Python?推荐 17 个在线的 Python 解释器!
作者:Al Sweigart 译者:豌豆花下猫@Python猫 英文:https://inventwithpython.com/blog/2022/10/30/17-online-python-ide ...
- ubuntu 安装anaconda3
ubuntu 安装anaconda3 官网:https://www.anaconda.com/ 下载:https://www.anaconda.com/products/individual#Down ...
- java学习之SpringMVC拦截器开发
0x00前言 springmvc的拦截器类似于Selvet的Filter,但是所属的操作又不一样 Spring MVC 提供了 Interceptor 拦截器机制,用于请求的预处理和后处理,也就是增强 ...
- Swagger的介绍
一.Swagger是什么? Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格的 Web 服务. 二.Swagger 的优势? 支持 API 自动生成同步的在线 ...
- 造个Python轮子,实现根据Excel生成Model和数据导入脚本
前言 最近遇到一个需求,有几十个Excel,每个的字段都不一样,然后都差不多是第一行是表头,后面几千上万的数据,需要把这些Excel中的数据全都加入某个已经上线的Django项目 这就需要每个Exce ...
- HTTPS - 揭秘 TLS 1.2 协议完整握手过程--此文为转发文,一定要结合wirshark工具看,很清楚
winshark 筛选条件为:tls and ip.src==xxx 本文通过对一次 TLS 握手过程的数据抓包分析做为切入点,希望能进一步的帮助大家理解 HTTPS 原理. HTTPS 是建立在 S ...
- Go语言核心36讲32
你好,我是郝林,今天我们继续分享原子操作的内容. 我们接着上一篇文章的内容继续聊,上一篇我们提到了,sync/atomic包中的函数可以做的原子操作有:加法(add).比较并交换(compare an ...
- libc-bin : Depends: libc6 (< 2.20) but 2.27-3ubuntu1 is installed问题解决
为了下载代码,在计算云上按照某个傻瓜文档操作后,ubuntu不仅没达到预定效果,反而无论如何操作,都出现 root@SZX1000450533:/var/lib/dpkg# apt-get autor ...