[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 ...
随机推荐
- 生成随机数的几种方法、Math.random()随机数的生成、Random()的使用
第一种方法使用:System.currentTimeMillis(); final long l = System.currentTimeMillis(); final int rs = (int) ...
- python face_recognition安装及各种应用
1.安装 首先,必须提前安装cmake.numpy.dlib,其中,由于博主所用的python版本是3.6.4(为了防止不兼容,所以用之前的版本),只能安装19.7.0及之前版本的dlib,所以直接p ...
- vue3学习记录(新特性)
总概 1) 性能提升 打包大小减少 41% 初次渲染快 55%,更新渲染快 133% 内存减少 54% 使用 Proxy 代替 defineProperty 实现数据响应式 重写虚拟 DOM 的实现和 ...
- MVC下拉框
<select> @{ foreach (var item in 循环泛型) { <option value="@item.ID">@item.属性名< ...
- 十四、资源控制器之RS
RC (ReplicationController )主要的作用就是用来确保容器应用的副本数始终保持在用户定义的副本数 .即如果有容器异常退出,会自动创建新的 Pod 来替代:而如果异常多出来的容器也 ...
- VMware Fusion配置NAT静态IP
前言 本主机 CentOS8.2 Mac VMware Fusion 我们在使用虚拟机的时候,经常遇到这样的问题,我们会换地方,IP 会变化,如果虚拟机使用桥接的方式,那么很多与 IP 相关的服务都会 ...
- VBA粗犷整理
PART1: 三.查找 1.从某一行向上/下找到第一个不为空的行 intRowPntEnd = ActiveSheet.Cells(intRowPntStart, intColPnt).End(xlD ...
- uniapp/微信小程序 项目day03
一.商品列表 1.1 获取数据 首先能够进入商品列表的途径 传的数据有 了解了这个之后就可以开始了,先创建分支 创建编译模式,并分配初试数据 这个时候就可以获取数据了 需要的数据 所以在发起请求之前需 ...
- 【题解】P7860 [COCI2015-2016#2] ARTUR
题面传送门 好题. 主要思路和另一位巨佬差不多,详细讲一下判断的部分. 解决思路: 首先考虑本题与拓扑排序有和关系.可以想到,某些棍子的先后移动顺序是有限制的.比如: 这里红色的必须比蓝色的先移动,因 ...
- volatile关键字在并发中有哪些作用?
作者:小牛呼噜噜 | https://xiaoniuhululu.com 计算机内功.JAVA源码.职业成长.项目实战.面试相关资料等更多精彩文章在公众号「小牛呼噜噜」 前言 读过笔者之前的一篇文章J ...