那些年搞不懂的"协变"和"逆变"

大壮他哥-专注于营销软件开发 大壮他哥-专注于营销软件开发     2022-08-06     326

关键词:

  博主之前也不是很清楚协变与逆变,今天在书上看到了有关于协变还是逆变的介绍感觉还是不太懂,后来看了一篇园子里面一位朋友的文章,顿时茅塞顿开。本文里面会有自己的一些见解也会引用博友的一些正文,希望通过本篇,能让大家对协变与逆变不再陌生。

What's 协变逆变?

  从字面理解协变就是"妥协的变化",而逆变则是"逆天的变化",哈哈,并不标准,我们来看看MSDN的解释:  

    “协变”是指能够使用与原始指定的派生类型相比,派生程度更大的类型。

    “逆变”则是指能够使用派生程度更小的类型。

  解释的很正确,大致就是这样,不过不够直白。通俗来讲,协变就是从小到大,逆变则是从大到小。。协变逆变只会出现在泛型类和委托中,下面我们通过例子来了解协变和逆变。

  

  按照我们的理解,Dog继承自Animal,所以Animal aAnimal = aDog; aDog 编辑器会隐式的转变为Animal。但是List<Dog> 不继承List<Animal> ,它们的身份是相等的,所以转换失败。

  如果想要转换的话我们可以使用以下的代码:

  List<Animal> animals= dogs.Select(c=>(Animal)c).ToList();

  这种写法太麻烦了,有没有一种方式可以直接赋值呢?答案是可以的,微软为了帮助我们开发人员简化这种写法,帮我们定义了Out和in两个关键字,我们看下官方对这两个关键字的解释:

  

  

  Out关键字可以简单的定义为返回值参数,只能作为返回值。

  In关键字则定义为输入型参数,其含义指In对应的类型在泛型成员中不能作为返回值。

  和刚开始说的一样,T 用out 标记,所以T代表了输出,也就是只能作为结果返回。

  

  因为T只能做结果返回,所以T不会被修改,编译器就可以推断下面的语句强制转换合法,所以一下代码编译通过

    IEnumerable<Animal> animals = dogs;  

 

  再看逆变,在Main函数中添加:

  1. Action<AnimalactionAnimal = new Action<Animal>(a => {/*让动物叫*/ });  
  2. Action<DogactionDog = actionAnimal;  
  3. actionDog(aDog); 

  很明显actionAnimal 是让动物叫,因为Dog是Animal,那么既然Animal 都能叫,Dog肯定也能叫。

  In 关键字:逆变,代表输入,代表着只能被使用,不能作为返回值,所以C#编译器可以根据in关键字推断这个泛型类型只能被使用,所以Action<Dog> actionDog = actionAnimal;可以通过编译器的检查。

  再次演示Out关键字:添加两个类:

  

  out关键字在上图中只用于返回值,所以编辑器不会报错。我们再来修改一下类

  

  如果泛型参数标记为out,泛型类成员参数又定义了T类型的话则编译不通过。同样的方法我们来测试下逆变:

  

 

总结

  Out:代表协变,只能当返回值类型使用,不能作为方法实参

  In:只能用作方法实参,不能用作返回值类型。

  我觉得只要上面两个概念搞懂了,在自己敲下Demo就没有问题了。

 

本文参考:http://www.cnblogs.com/majiang/articles/2607990.html

  

那些年搞不懂的术语概念:协变逆变不变体

简述什么是协变性、逆变性、不变性协变性,如:string->object(子类到父类的转换)逆变性,如:object->string(父类到子类的转换)不变性,基于上面两种情况,不可变。具体下面再做分析。泛型委托的可变性先使用框架定... 查看详情

那些年搞不懂的多线程同步异步及阻塞和非阻塞---多线程简介

1、进程和线程的概念进程:运行中的应用程序称为进程,拥有系统资源(cpu、内存)线程:进程中的一段代码,一个进程中可以有多段代码。本身不拥有资源(共享所在进程的资源);在java中,程序入口被自动创建为主线程,... 查看详情

上周热点回顾(8.29-9.4)

...实战案例-------架构优化之清爽一夏(Double_K)· 那些年搞不懂的术语、概念:协变、逆变、不变体(农码一生)· 【无私分享:ASP.NETCORE项目实战(第十二章)】添加对SqlServer、MySql、Oracle的支持(果 查看详情

搞不懂的github

我也是在网上看了不少的教程,但还是一脸懵逼。首先还是先写出自己的github的地址吧。我的github地址为:https://github.com/UchinoMENG.这个网址里面还是有一些东西的,但都是瞎折鼓得,自己也不太懂。可能自己下的功夫不够,所以... 查看详情

html里面area标签的这个例子我搞不懂,求高手帮忙。。。

<html><body><p>请点击图像上的星球,把它们放大。</p><imgsrc="http://www.w3school.com.cn/i/eg_planets.jpg"border="0"usemap="#planetmap"alt="Planets"/><mapname="planetmap"id="planetmap"><a... 查看详情

java进阶知识点2:看不懂的代码-协变与逆变

要搞懂Java中的协办与逆变,不得不从继承说起,如果没有继承,协变与逆变也天然不存在了。我们知道,在Java的世界中,存在继承机制。比如MochaCoffee类是Coffee类的派生类,那么我们可以在任何时候使用MochaCoffee类的引用去替换... 查看详情

tf-搞不懂的tf矩阵加法

看谷歌的demomnist,卷积后加偏执量的代码h_conv1=tf.nn.relu(conv2d(x_image,W_conv1)+b_conv1)h_pool1=max_pool_2x2(h_conv1)其中的x_image的维数是[-1,28,28,1],W_conv1的维数是[5,5,1,32],b的维数是[32]conv2d对x_image和W_conv1进行卷积,结果为[-1,28,2 查看详情

搞不懂的算法-排序篇

  最近在学习算法,跟着<Algorithms>这本书,可能是自己水平不够吧,看完排序算法后各种,希尔,归并,快排,堆的实现在脑子里乱成一锅粥,所以就打算大概总结一下,不求精确,全面,只想用平白的语言来理一理,如... 查看详情

看孙鑫vc视频第7章,vc编译出现错误,不懂的是哪里错误

由于是初学MFC有点菜,希望高手哥哥多多指点增加菜单项然后点击弹出对话框我按照视频里老师讲的一步步做的啊不知道为什么编译错误。#include"stdafx.h"#include"benyixi.h"#include"benyixiDoc.h"#include"benyixiView.h&... 查看详情

easyui中dialog的问题,懂的来,不懂别装懂!

在jsp页面中有一个<divid="brandAdd_dialog"></div>,在js文件中有一个控制他显示的方法functionshowAddDialog() $('#brandAdd_dialog').dialog( title:'添加', width:400, height:200, closed:false, cache:false, modal:true );这个dialog中有一个... 查看详情

htmlobject标签怎么使用

...图片上地图里的每个地方指向的链接都不同该怎么用实在搞不懂了<objectdata="../picture/acoustics.jpg"usemap="#map1"></object>这是书里给的第一行命令后面的自己不会有高手帮忙解释下谢谢顺便把这种链接该怎么写... 查看详情

spring基于自动装配的依赖注入详解[自动装配模式搞不懂?来看就完了!!!][autowire属性值详解][自动装配的6种模式](代码片段)

您的“关注”和“点赞”,是信任,是认可,是支持,是动力......如意见相佐,可留言。本人必将竭尽全力试图做到准确和全面,终其一生进行修改补充更新。目录1Spring基于自动装配的依赖注入概述2自动装配的局限性3案例实操... 查看详情

关于spring配置事务的问题,也写过不少代码,可是底层配置的那些东西,总看不懂,别闲我菜啊,哈哈

...g配置的事务执行?这些方法是哪些方法呢?是sping管理的那些bean下的方法吗?<!--配置事务传播特性--> <!--共有7种事务隔离级别 1.PROPAGATION_REQUIRED:如果当前没有事务,就新建一个事务,如 查看详情

java数字和字母混合排序

...351288K3K5K12K88想变成统一路线,即3K35K512K1288K88我JAVA基本是不懂的,只能大致改改,选择排序条件的按钮上是这样的代码<selectname="sort_condition"style="width:60px;"><optionvalue="LX">路线在后面的代码里是这样... 查看详情

为 Python 3 安装 IPython 时出错:sys_platform == "darwin" 和 platform_python_implementation == &qu

】为Python3安装IPython时出错:sys_platform=="darwin"和platform_python_implementation=="CPython"【英文标题】:ErroroninstallingIPythonforPython3:sys_platform=="darwin"andplatform_python_implementation==" 查看详情

quickftpserver怎么使用

...出以下界面,进行权限设置,就是对这个ftp账户名指定有那些权限,一般有上传、下载、删除、创建目录等权限,这里你可以全部选中。下载和上传速度限制为0的话是不限速。  5、设置完成后,软件运行!参考技术A在路由器... 查看详情

怎么用java向数据库中添加和删除数据?

实在是搞不懂了。我用的是Access,在数据源中建了一张叫Other1的表,表里面有两个项目,id和key,id是主键,用于标识条目数,key类型是文本。现在表里已经有两条记录,id分别为1和2,想再添一个key。publicstaticvoidmain(Stringargs[])Conne... 查看详情

angular中ng-repeat是啥意思

...环输出指定次数的HTML元素。集合必须是数组或对象。看不懂的话把这段代码拷贝到你的html里自己在浏览器上运行看实例:<!DOCTYPEhtml><html><head><metacharset="utf-8"><scriptsrc="http://cdn.static.runoob.com/libs/angu... 查看详情