C#提供了一组关键字in&out,在泛型接口泛型委托中,若不使用关键字修饰类型参数T,则该类型参数是不可变的(即不允许协变/逆变转换),若使用in修饰类型参数T,保证“只将T用于输入”,则允许T的逆变转换;若使用out修饰类型参数T,保证“只将T用于输出”,则允许T的协变转换。下面我们解释两个问题:

  • 为什么类型参数T仅用于输出时可以进行协变转换?
  • 为什么类型参数T仅用于输入时可以进行逆变转换?
//定义两个类型
class Animal {}
class Dog : Animal {} //定义两个泛型委托
delegate T OutputOnly<T>(); //只将类型参数T用于输出
delegate void ForInput<T>(T obj); //将类型参数T用于输入 //此时协变的含义是:允许将xxx<Dog>类型的委托转换为xxx<Animal>类型的委托 //对于OutputOnly<T>委托:
OutputOnly<Dog> ood = ReturnADog; //一个假设的符合该委托约束条件的方法,返回一个Dog对象
//对委托类型进行协变转换:
OutputOnly<Animal> ooa = ood;
Animal an = ooa.Invoke();
//调用ooa委托时,它期望获取一个Animal对象,而ooa委托实际保存的ReturnADog方法会返回一个Dog对象,
//对于ooa委托来说,它成功获取到了一个Animal对象,所以在仅输出时协变转换是合法的 //对于ForInput<T>委托:
ForInput<Dog> fid = NeedADog; //一个假设的符合该委托约束条件的方法,要求传入一个Dog对象
//对委托类型进行协变转换:
ForInput<Animal> fia = fid;
fia.Invoke(new Animal());
//调用fia委托时,fia根据要求传入一个Animal对象,而此时fia委托实际保存的方法需要一个Dog对象
//所以传入的Animal对象不符合要求。fia委托其实是懵逼的,因为在它看来你要的就是Animal啊,
//它并不知道实际需要的是Dog对象,所以当将参数T用于输入时,协变转换是非法的 //此时逆变的含义是:允许将xxx<Animal>类型的委托转换为xxx<Dog>类型的委托 //对于ForInput<T>委托:
ForInput<Animal> fia = NeedAAnimal; //一个假设的符合该委托约束条件的方法,要求传入一个Animal
//对委托类型进行逆变转换
ForInput<Dog> fid = fia;
fid.Invoke(new Dog());
//调用fid委托时,fid根据要求传入一个Dog对象,而此时fid委托实际保存的方法需要一个Animal对象
//所以fid委托传入的对象符合要求,所以在用于输入时逆变转换是合法的 //对于OutputOnly<T>委托:
OutputOnly<Animal> ooa = ReturnAAnimal; //一个假设的符合该委托约束条件的方法,返回一个Animal
//对委托类型进行逆变转换
OutputOnly<Dog> ood = ooa;
Dog dog = ood.Invoke();
//调用ood委托时,它期望获取一个Dog对象,而ood委托实际保存的ReturnAAnimal方法会返回一个Animal
//所以ood委托等于是被骗了,它想要的根本不是Animal对象,所以在用于输出时逆变转换是非法的

由此可见,仅用于输出时协变转换才合法,仅用于输入时逆变转换才合法,而in&out关键字正是C#语言设计的用来监督用户“你想用协变/逆变可以,但不许瞎搞类型转换”的关键字,可以说是很优秀的一个特性了。

C#的in/out关键字与协变逆变的更多相关文章

  1. 解读经典《C#高级编程》最全泛型协变逆变解读 页127-131.章4

    前言 本篇继续讲解泛型.上一篇讲解了泛型类的定义细节.本篇继续讲解泛型接口. 泛型接口 使用泛型可定义接口,即在接口中定义的方法可以带泛型参数.然后由继承接口的类实现泛型方法.用法和继承泛型类基本没有 ...

  2. C#中泛型方法与泛型接口 C#泛型接口 List<IAll> arssr = new List<IAll>(); interface IPerson<T> c# List<接口>小技巧 泛型接口协变逆变的几个问题

    http://blog.csdn.net/aladdinty/article/details/3486532 using System; using System.Collections.Generi ...

  3. Programming In Scala笔记-第十九章、类型参数,协变逆变,上界下界

    本章主要讲Scala中的类型参数化.本章主要分成三个部分,第一部分实现一个函数式队列的数据结构,第二部分实现该结构的内部细节,最后一个部分解释其中的关键知识点.接下来的实例中将该函数式队列命名为Que ...

  4. java协变逆变,PECS

    public static void main(String[] args) { // Object <- Fruit <- Apple <- RedApple System.out ...

  5. 协变 & 逆变

    都跟里氏替换原则有关. 协变:你可以用一个子类对象去替换相应的一个父类对象,这是完全符合里氏替换原则的,和协(谐)的变.如:用Swan替换Bird. 逆变:你可以用一个父类对象去替换相应的一个子类对象 ...

  6. C#核心语法讲解-泛型(详细讲解泛型方法、泛型类、泛型接口、泛型约束,了解协变逆变)

    泛型(generic)是C#语言2.0和通用语言运行时(CLR)的一个新特性.泛型为.NET框架引入了类型参数(type parameters)的概念.类型参数使得设计类和方法时,不必确定一个或多个具 ...

  7. C#核心语法-泛型(详细讲解泛型方法、泛型类、泛型接口、泛型约束,了解协变逆变)

    泛型(generic)是C#语言2.0和通用语言运行时(CLR)的一个新特性.泛型为.NET框架引入了类型参数(type parameters)的概念.类型参数使得设计类和方法时,不必确定一个或多个具 ...

  8. 编写高质量代码改善C#程序的157个建议[协变和逆变]

    前言 本文已更新至http://www.cnblogs.com/aehyok/p/3624579.html .本文主要学习记录以下内容: 建议42.使用泛型参数兼容泛型接口的不可变性 建议43.让接口 ...

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

    转自:http://www.cnblogs.com/jingzhongliumei/archive/2012/07/02/2573149.html 先做点准备工作,定义两个类:Animal类和其子类D ...

随机推荐

  1. 曼孚科技:“四管齐下”筑牢AI数据隐私安全防线

    谈及数据,绕不开的一个话题就是数据隐私与数据安全.随着数字化进程加快,数据安全事件频发,据Risk Based Security统计,去年国际数据泄露事件近5000起,被泄露数据近41亿条,数据造成的 ...

  2. 读《疯狂Java讲义》笔记总结一

    最近在读<疯狂Java讲义>,现把其中遇到的一些自己以前没掌握的点儿记录下来. 1.字符串相关 字符串不是基本类型,字符串是一个类,也就是一个引用类型. 字符串转int类型String a ...

  3. Metasploit生成木马入侵安卓手机

    开始 首先你需要一个Metasploit(废话) Linux: sudo apt install metasploit-framework Termux: 看这里 指令 sudo su //生成木马文 ...

  4. Javascript中字符串常用方法

    JavaScript字符串常用方法 (1)获取相应位置的字符(charAt()) var str="你好,小小鸟!" var s=str.charAt(1) //获取到索引为1的字 ...

  5. Centos下安装Scala(1)

    1.登录centos至root角色下 配置环境变量 2.执行下述命令 scala -version 出现结果如下 输入 'y' 3.开始安装 4.安装完成界面 5.启动成功以及测试程序

  6. thanos的日志能不能打到文件里面去?

    不行. thanos/pkg/logging/logger.go: logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)) if logF ...

  7. CMake语法—内置变量

    目录 CMake语法-内置变量 1 CMake变量分类 1.1 普通变量 1.2 缓存变量 1.3 环境变量 1.4 内置变量 2 CMake内置变量分类 2.1 提供信息的变量 2.2 改变行为的变 ...

  8. 一、neo4j中文文档-入门指南

    目录 neo4j中文文档-入门指南 Neo4j v4.4 neo4j **Cypher ** 开始使用 Neo4j 1. 安装 Neo4j 2. 文档 图数据库概念 1. 示例图 2.节点 3. 节点 ...

  9. centos6.6手动安装mysql5.5并配置主从同步

    0.实验环境 主机IP(Master) 192.168.61.150 centos6.6 从机IP(Slave)   192.168.61.157 centos6.6 1.查看centos系统版本 [ ...

  10. WebGPU 中消失的 VAO

    1 VAO 是 OpenGL 技术中提出来的 参考: 外链 其中有一段文字记录了 VAO 是什么: A Vertex Array Object (VAO) is an object which con ...