首页 > 其他分享 >五分钟看完,彻底理解协变逆变

五分钟看完,彻底理解协变逆变

时间:2023-08-11 09:57:18浏览次数:34  
标签:逆变 协变 Person 五分钟 IWork 泛型 Out

其实这是c#的老知识点了,但是今天发现同事对这个竟然还一知半解,就和他们讲解了下,顺便也回顾了下,同事我也把我对这个的全部理解,融化成几分钟的讲解,保证大家5分钟内全部理解,看不懂来打我。

目录

协变、逆变 解决的问题

泛型类型转换

比如Person类是Student的父类,我们平时可以直接:

Person A = new Student();

这是所谓的隐式转换,相信百分之999.99%的人都知道。
然后随着大家写代码越来越多,就会遇到这样的场景。

//我有一个集合
//我手上有一批学生
IEnumerable<Student> students = new List<Student>();
//我要他们先做人
IEnumerable<Person> peoples = students;

第一次看到这种代码,其实哪怕你一点不知道协变,逆变,你也觉得这是一段正常不过的代码,因为每个学生都是人,都可以直接转成 这个类型,那我一批学生不就是一批人吗。是的,你这样想绝对没错,不然微软怎么会能让你这样写没问题还编译通过呢?
但是如果我自己写一个:

//定义一个工作的泛型接口
public interface IWork<T> 
{
            
}

实现类
public class Work<T> : IWork<T> 
{
            
}

//直接报错
IWork<Person> work = new Work<Student>();;

现实给了我们当头一棒,这时候,我们应该找到 IEnumerable,选中然后狠狠的F12去看一下,为什么官方的就可以。

我们发现官方在泛型前面多了一个out关键字。破案了~
现在我们在我们的代码中也加入out关键字

public interface IWork<out T> 
{
            
}

public class Work<T> : IWork<T> 
{
            
}
IWork<Person> work = new Work<Student>();

OK~代码正常运行。

原则核心

这里开始我们挑战五分钟速通,如果按照正常博客上来先讲概念,别说五分钟了,可能大家也就迷迷糊糊地看完了,所以我们直接整活。

核心依据

正如数学的发展是从1+1=2作为开始,我们也需要一些真理来支撑我们讲下去。那么我们的核心依据就是:
里氏替换——C#里,子类转父类可以直接隐式转换
就这么短,就完事了?对,记住就行!!!

Out/In 输入输出?

讲到这里,我们继续忽悠,out是啥?来个翻译!不就是输出吗?in是啥,不就是输入吗?那么带入一下,Out不就是返回值吗,In不就是入参吗。那不就是方法的特征么。(先假设,再假设)

In:那么根据核心依据,子类转父类可以直接转,入参如果限定是Person类型,那么你给我限定为Student或者任意的Person类型的派生类,我都是可以接受的,因为都是安全的,可以直接转换过来的。

这种从基类转向派生类的兼容,就是所谓的逆变。
说白了,我让你给我一个人,你说不行,我给你找个学生,那肯定是满足需求的。

Out:Out代表的是返回值,根据核心依据,我返回的是Student类型,你说不行,你给我返回Person类型,那我不是笑开花了,我连Student都能返回,你让我返回父类,那我不是直接转就过去了,总归是类型安全的。

这种从派生类转向基类的兼容,就是所谓的协变。
说白了,我可以造个学生,结果你说给个人就行, 那不是so easy。

In示意图

Out示意图

证明

好了,我们说了这么多,至少证明下In/Out是代表的入参和返回值吧?直接show you code:
当Out作为返回值时的泛型没有问题,但是入参就报错了

当In作为入参时的泛型没有问题,但是返回值就报错了

好了,这还需要再解释吗?最后我们总结下,逆变和协变就是让方法有了泛型类型上的转换能力,强化了方法的多态能力。

问题点

1.属性为啥可以用逆变协变?
属性不就是get/set方法。
2.为什么接口和委托可以用逆变协变,类不行?
拜托你找一下共同点,接口和委托的共同点,都是行为,也就是方法为核心。接口里不能有字段。这也印证了我说的逆变协变最终是为方法服务的。
之所以类不行,我大概理解是方法和实例是分开的,本身不和实例存储在一起,也不是每个实例一份,如果逆变和协变可以服务类,那么会出现同样的类型,但是每个实例内部的同一个字段的类型都不一样,这对于存储和类型安全都是问题。
3.逆变和协变有啥用?
当你...设计问题,我就有遇到,有时候用上能更加优雅或者灵活的写代码吧,看你吧,少年。

标签:逆变,协变,Person,五分钟,IWork,泛型,Out
From: https://www.cnblogs.com/qwqwQAQ/p/17622254.html

相关文章

  • 5分钟彻底理解逆变协变,学不会来打我
    其实这是c#的老知识点了,但是今天发现同事对这个竟然还一知半解,就和他们讲解了下,顺便也回顾了下,同事我也把我对这个的全部理解,融化成几分钟的讲解,保证大家5分钟内全部理解,看不懂来打我。最后,都说c#断层严重,希望广大.neter振作起来,不要呆在舒适圈啦。目录协变、逆变解决的问题泛......
  • 腾讯云TCB云函数趣应用:巧用 puppeteer 五分钟实现一个云加社区个人成就爬虫...
    技术选型应用思路核心代码参数介绍HTTP访问注意事项参考资料最后奉上几个社区大佬的成就#技术选型之前一直想用云函数来做爬虫,无奈小程序云开发的云函数还未完全支持puppeteer,调用会报错。但是最近发现TCB的云函数支持puppeteer依赖,就决定用它了。另外一个原因就是它也......
  • VimScript五分钟入门-中文翻译
    这篇文章主要是为了让你能够尽可能快地学习到vimscript的基础。你可以把这当做一个速查表。在读这篇文章之前,你应该可能已经有了一些编程经验。Vim的内建文档已经很出色了。你可以在vim里尝试:h<searchterm>来阅读更多信息。你可以通过在normal模式下键入gQ命令启动REPL环境来调......
  • 五分钟教你使用GitHub寻找优质项目
    https://www.cnblogs.com/Can-daydayup/p/17581307.html 思维导航前言首先解决访问慢的问题GitHub热门栏目GitHub上直接搜项目GitHub搜索小技巧前言经常会有同学会问如何使用GitHub找到自己想要的项目,今天咱们就出一期快速入门教程五分钟教你使用GitHub寻找优质项......
  • 五分钟教你使用GitHub寻找优质项目
    前言经常会有同学会问如何使用GitHub找到自己想要的项目,今天咱们就出一期快速入门教程五分钟教你使用GitHub寻找优质项目。GitHub作为世界上最大的项目开源平台之一,上面有着无数优质的开源项目。善于使用它能够让你获得很多意想不到的惊喜。首先解决访问慢的问题FastGithub是Gi......
  • 五分钟了解制造业核心系统的双向集成
    大家好,我是Edison。上一篇,我们了解制造行业核心的5大系统MES、ERP、WMS、PLM和SCADA是如何连接从而实现数据共享的。本篇,我们来了解一下制造行业工业软件的集成,一是纵向的集成,二是横向的集成。信息系统集成图片来源:后厂造上图粗略描述了制造行业工业软件信息系统在横向和纵向......
  • 光伏三相并网仿真 模型内容: 1.光伏+MPPT控制+两级式并网逆变器
    光伏三相并网仿真模型内容:1.光伏+MPPT控制+两级式并网逆变器(boost+三相桥式逆变)2.坐标变换+锁相环+dq功率控制+解耦控制+电流内环电压外环控制+spwm调制3.LCL滤波仿真结果:1.逆变输出与三项380V电网同频同相2.直流母线电压800V稳定3.d轴电压稳定311V;q轴电压稳定为0V,有功功率高效输......
  • 单相全桥逆变器仿真,simulink,matlab
    单相全桥逆变器仿真,simulink,matlabYYID:3830657097395087......
  • Three_Phase_Inverter_3Level:基于MATALB/Simulink的三相三电平SVPWM逆变器仿真模型。
    Three_Phase_Inverter_3Level:基于MATALB/Simulink的三相三电平SVPWM逆变器仿真模型。仿真条件:MATLAB/SimulinkR2015bID:2780651351004554......
  • SVPWM_Inverter_Inductor_Motor:基于MATLAB/Simulink的空间矢量脉宽调制SVPWM逆变器,交
    SVPWM_Inverter_Inductor_Motor:基于MATLAB/Simulink的空间矢量脉宽调制SVPWM逆变器,交流测连接三相感应电机。仿真条件:MATLAB/SimulinkR2015bID:59100650372688846......