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. 校招——面试(Android岗)总结

    PS:持续更新,未完待续 2016.8.24某为面试 自我介绍一下 链表和数组的区别 数组的存储空间是静态.连续分布的,初始化过大会造成空间浪费,过小会使空间溢出:链表的存储空间是动态分布的,只要内存 ...

  2. LATEX图片位置

    常用选项[htbp]是浮动格式: -『h』当前位置.将图形放置在正文文本中给出该图形环境的地方.如果本页所剩的页面不够,这一参数将不起作用. -『t』顶部.将图形放置在页面的顶部. -『b』底部.将图 ...

  3. python技巧一行命令搞定局域网共享

    python超强玩法--一行命令搞定局域网共享 ​ 今天刷到python的一个新玩法,利用python自带的http服务,快速创建局域网共享服务,命令如下: python -m thhp.server ...

  4. gin框架中项目的初始化

    核心知识点 json配置文件解析成结构体 将路由对应的接口抽离到单独的文件中,main函数中直接注册路由即可 项目目录图 项目代码 app.json代码 { "app_name": ...

  5. vue 项目npm run dev ip访问

    webpack npm run dev 不能通过ip访问 只能通过localhost访问 解决方法如下: 修改vue-cli: config/index.js 文件 把文件中 host 的值,改成 i ...

  6. 在Excel VBA中写SQL,是一种什么体验

    每每提到Excel办公自动化,我们脑海里能想到的就是公式.数据透视表.宏.VBA,这也是我们大部分人数据分析的进阶之路.当我们对于常用VBA技巧已经相当熟练后,往往会有一种"我的VBA知识够 ...

  7. 一步一步超级详细的zabbix安装教程

    安装说明: 1. 虚拟机上安装两台全新Linux: zabbix-server:192.168.255.128 zabbix-agent :192.168.255.129 2. zabbix-serv ...

  8. 005 Linux 命令三剑客之-sed

    grep:数据查找定位 awk:数据切片,数据格式化,功能最复杂 sed:数据修改 01 Linux 命令三剑客? 三剑客各有所长,和锅锅一一搞起就是了! sed:擅长数据修改. grep:擅长数据查 ...

  9. 1. flink 基础

    flink word count  程序 1. 数据集模式 pom.xml 文件 <?xml version="1.0" encoding="UTF-8" ...

  10. springboot 配置百里香 thymeleaf?

    一.1.1父级工程导入jar包. springboot已经完整把thymeleaf集成进框架中了,可以直接添加使用不需要任何的配置信息 <dependency> <groupId&g ...