【从零开始入门unity游戏开发之——C#篇36】C#的out协变和in逆变如何解决泛型委托的类型转换问题

news2025/2/4 6:38:19

文章目录

  • 一、知识回顾和问题分析
    • 1、回顾`强制转换`和`as`转换知识
    • 2、问题分析
  • 二、为什么泛型委托不行?
    • 1、泛型类型的严格类型检查
    • 2、**`as` 和强制类型转换不能直接使用**
  • 三、如何解决这个问题?
    • 1、**协变(`out`)**
    • 2、**逆变(`in`)**
  • 四、**应用场景**
  • 五、总结
  • 六、系统泛型委托和协变、逆变
  • 专栏推荐
  • 完结

一、知识回顾和问题分析

1、回顾强制转换as转换知识

前面我们已经学过强制转换as转换

  • 强制类型转换((T)):用于将一个对象显式地转换为指定的类型。如果转换不成功,通常会抛出 InvalidCastException。
  • as 操作符:用于尝试将对象转换为指定类型。如果转换失败,返回 null,而不是抛出异常。
//注意Dog是Animal的子类
Animal animal = new Dog();

//强制类型转换
Dog dog = (Dog)animal;

//as 操作符
Dog dog = animal as Dog;

2、问题分析

根据里氏替换原则:可以用子类替换掉父类

前面我们学习了泛型,那我们可不可以使用强制类型转换或者as 操作符将泛型委托从一个类型转换到另一个类型?

答案是不行的

二、为什么泛型委托不行?

1、泛型类型的严格类型检查

在 C# 中,泛型类型是 严格的类型检查,意味着即使存在继承关系(比如 Son 继承自 Father),泛型类型参数 也被视为不同的类型。也就是说,Produce<Father>Produce<Son> 被认为是两个 不同的类型,即便 Son 是 Father 的子类。

举例:

public delegate T Produce<T>();

Produce<Son> produceSon = () => new Son();
Produce<Father> produceFather = produceSon;  // 编译错误

编译器报错的原因是 泛型类型 Produce<T> 在内部对类型参数进行检查,不会因为 Son 是 Father 的子类而认为 Produce<Son> 可以转换为 Produce<Father>

2、as 和强制类型转换不能直接使用

as 操作符和强制类型转换((T))只对相同的类型派生类型有效,泛型类型是严格类型检查的,所以不行。

例如:

Produce<Father> produceFather = produceSon as Produce<Father>;  // 编译错误

因为 Produce<Son>Produce<Father> 不是相同的类型,produceSonproduceFather 无法通过 as 或强制类型转换直接转换。

三、如何解决这个问题?

为了处理这种类型严格检查的问题,C# 引入了协变逆变,通过这些机制我们可以在泛型中更好地处理继承关系,使得泛型类型可以遵循里氏替换原则

通过使用 out(协变)和 in(逆变)修饰符,C# 显式支持泛型委托的类型转换规则,从而允许不同类型之间的转换,且不破坏类型安全。

1、协变(out

通过协变(out 关键字),你可以让泛型委托支持返回值的类型转换:

public delegate T Produce<out T>();

Produce<Son> produceSon = () => new Son();
Produce<Father> produceFather = produceSon;  // 现在是合法的,协变支持
Father father = produceFather();  // 实际返回的是 Son 类型的对象

这里的关键是 Produce<T> 泛型委托的类型参数 T 使用了 out 关键字,这表示这个委托仅作为返回值使用(即输出类型)。

协变的原理是,如果 SonFather 的子类,那么 Produce<Son> 可以被视作 Produce<Father>,从而实现类型转换。

2、逆变(in

通过逆变(in 关键字),你可以让泛型委托支持输入参数的类型转换:

public delegate void Consume<in T>(T item);

Consume<Father> consumeFather = item => Console.WriteLine("Consuming Father");
Consume<Son> consumeSon = consumeFather;  // 逆变支持,合法
consumeSon(new Son());  // 实际调用的是 consumeFather

在这个例子中,Consume<T> 泛型委托的类型参数 T 使用了 in 关键字,表示它仅作为输入参数使用。

逆变的原理是,如果 SonFather 的子类,那么 Consume<Father> 可以被视作 Consume<Son>,从而实现类型转换。

四、应用场景

协变和逆变主要用于泛型接口泛型委托的类型约束中,可以有效提高代码的灵活性和类型安全性。

五、总结

为了使泛型类型可以遵循里氏替换原则,C# 引入了协变逆变,通过这些机制我们可以在泛型中更好地处理继承关系。

outin 的引入正是为了 安全地实现类型转换,而不会导致不兼容类型之间的隐式转换问题。在没有 outin 的情况下,泛型类型参数的转换是不允许的。

六、系统泛型委托和协变、逆变

在 C# 的实际开发中,我们并不需要手动使用 out 和 in 来实现协变和逆变,因为 Action<>Func<> 这些常用的系统泛型委托,C# 编译器已经默认对输入参数和返回值进行了协变和逆变的处理。
在这里插入图片描述
在这里插入图片描述
这里主要是要理解out和in的原理,和意义,可能在面试题中会被问到原理性的知识。


专栏推荐

地址
【从零开始入门unity游戏开发之——C#篇】
【从零开始入门unity游戏开发之——unity篇】
【制作100个Unity游戏】
【推荐100个unity插件】
【实现100个unity特效】
【unity框架开发】

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇,https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!如果你遇到任何问题,也欢迎你评论私信或者加群找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2268298.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习使用Anaconda打开Jupyter Notebook编码

新手入门深度学习使用Anaconda打开Jupyter Notebook编码 1. 安装Anaconda 第一种是Anaconda官网下载安装包&#xff0c;但是很慢&#xff0c;不太建议 第二种使用国内清华大学镜像源下载 选择适合自己电脑的版本&#xff0c;支持windows&#xff0c;linux系统 下载完之后自行…

Linux套接字通信学习

Linux套接字通信 代码源码&#xff1a;https://github.com/say-Hai/TcpSocketLearn/tree/CThreadSocket 在网络通信的时候, 程序猿需要负责的应用层数据的处理(最上层)&#xff0c;而底层的数据封装与解封装&#xff08;如TCP/IP协议栈的功能&#xff09;通常由操作系统、网络协…

git clone 和 conda 换源

文章目录 git clone 通过 sshconda 创建虚拟环境通过 env.yml 文件conda 换源 git clone 通过 ssh git clone ssh://用户名IP地址:/仓库名字.gitconda 创建虚拟环境通过 env.yml 文件 conda env create -f environment.ymlconda 换源 Step 1 生成 .bashrc 文件在家目录下。…

机床数据采集网关在某机械制造企业的应用

随着工业4.0时代的到来&#xff0c;智能制造已成为制造业转型升级的重要方向。数控机床作为现代制造业的核心设备&#xff0c;其运行状态和加工参数的数据实时采集与分析对于提升生产效率、优化生产流程具有关键意义。 背景概述 某机械制造企业拥有多台数控机床&#xff0c;这…

c# RSA加解密工具,.netRSA加解密工具

软件介绍 名称: c# RSA加解密工具,.netRSA加解密工具依赖.net版本: .net 8.0工具类型: WinForm源码下载 c# RSA加解密工具,.netRSA加解密工具 依赖项 WinFormsRSA.csproj <Project

穷举vs暴搜vs深搜vs回溯vs剪枝_全排列_子集

46. 全排列 递归解决&#xff1a;一开始选一个数&#xff0c;递归进入下一层再选一个新的数&#xff0c;直到到最后一个数。反会上一层遍历其它数。 每次递归到叶子节点就找到了一种组合&#xff0c;思路有了具体怎么实现&#xff1f; 1.怎么记录每条路径&#xff1f; 定义一个…

【Trick】获取kaggle账号的token和api(用于数据集下载)

0&#xff1a;操作背景 由于未来的科研需要用到Unet&#xff0c;但是运行学长的史山代码无法跑通&#xff0c;自己写了一个Unet并load学长的数据集效果也很差&#xff0c;于是打算从最最基础的开始&#xff0c;上github调用一个Unet并成功在公有数据集上跑一遍实例。 Unet的g…

VS Code AI开发之Copilot配置和使用详解

随着AI开发工具的迅速发展&#xff0c;GitHub Copilot在Cursor、Winsuf、V0等一众工具的冲击下&#xff0c;推出了免费版本。接下来&#xff0c;我将为大家介绍GitHub Copilot的配置和使用方法。GitHub Copilot基于OpenAI Codex模型&#xff0c;旨在为软件开发者提供智能化的代…

论文解读 | NeurIPS'24 Lambda:学习匹配先验以处理无标记垂悬问题场景下的实体对齐任务...

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 点击 阅读原文 观看作者讲解回放&#xff01; 作者简介 尹航&#xff0c;上海交通大学博士生 内容简介 我们研究了带有无标记悬挂问题的实体对齐&#xff08;EA&#xff09;任务&#xff0c;即部分实体在另一个…

评分模型在路网通勤习惯分析中的应用——提出问题(1)

1、问题的由来、目标和意义 最近一段时间和公司其它业务部门讨论时&#xff0c;发现一个有趣的交通路网问题&#xff0c;车辆从S点行驶到V点共用时40分钟&#xff0c;这段时间内路网中的卡口摄像头识别到了车辆通过的信息。如下图所示&#xff1a; 设计师需要通过这些有限的路…

Spring Security day 11.23

ok了今天学习一个关于登录角色权限的管理框架&#xff0c;我们一起取看看吧 一.权限控制 1.1 认证和授权概念 前面我们已经完成了后台管理系统的部分功能&#xff0c;例如检查项管 理、检查组管理、套餐管理、预约设置等。接下来我们需要思 考 2 个问题&#xff1a; 问题 1 …

【IC验证】verilog及systemverilog特殊特性的分析

verilog及systemverilog特殊特性的分析 1.概述2.赋值延迟&#xff08;0&#xff09;总结&#xff08;1&#xff09;情况一&#xff1a;initial中进行阻塞赋值和非阻塞赋值&#xff08;不延迟&#xff09;a代码b 电路图c 结果 &#xff08;2&#xff09;时钟a 代码b 电路图c 结果…

FPGA流水线考虑因素

流水线考虑因素 另一种提升性能的方法是对拥有多个逻辑级数的长数据路径进行重新组织&#xff0c;并将其分配在多个时钟周期上。这种方法 以时延和流水线开销逻辑管理为代价&#xff0c;来达到加快时钟周期和提高数据吞吐量的目的。 由于 FPGA 器件带有大量的寄存器&#x…

关于 PCB线路板细节锣槽问题 的解决方法

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/144783817 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…

SQL创建和操纵表

本文介绍创建、更改和删除表的基本知识。 1. 创建表 SQL 不仅用于表数据操纵&#xff0c;而且还用来执行数据库和表的所有操作&#xff0c;包括表本身的创建和处理。一般有两种创建表的方法&#xff1a; 多数DBMS 都具有交互式创建和管理数据库表的工具&#xff1b;表也可以…

RPA系列-uipath 学习笔记4

使用Uipath 处理hover的问题 备注&#xff1a;使用uipath stversion&#xff1a;2024.10.6,所有学习来源自uipath Academy 首先&#xff0c;打开uipath给我们提供的一个网站 ACME,这个网站呢&#xff0c;需要提前注册一下的哈。 今天呢&#xff0c;就是记录一下&#xff0c;怎…

Unity编译Android apk包进度奇慢或gradle报错的解决方案

最近遇到Unity编译Android apk进度卡在"Calling IPostGenerateGradleAndroidProject callbacks"进度一直不变&#xff0c;如下图&#xff1a; 最后提示编译失败&#xff0c;类似错误如下&#xff1a; Picked up JAVA_TOOL_OPTIONS: -Dfile.encodingUTF-8FAILURE: Bu…

探究音频丢字位置和丢字时间对pesq分数的影响

丢字的本质 丢字的本质是在一段音频中一小段数据变为0 丢字对主观感受的影响 1. 丢字位置 丢字的位置对感知效果有很大影响。如果丢字发生在音频信号的静音部分或低能量部分&#xff0c;感知可能不明显&#xff1b;而如果丢字发生在高能量部分或关键音素上&#xff0c;感知…

CAT3D: Create Anything in 3D with Multi-View Diffusion Models 论文解读

24年5月的论文&#xff0c;上一版就是ReconFusion 目录 一、概述 二、相关工作 1、2D先验 2、相机条件下的2D先验 3、多视角先验 4、视频先验 5、前馈方法 三、Method 1、多视角扩散模型 2、新视角生成 3、3D重建 一、概述 该论文提出一种CAT3D方法&#xff0c;实现…

模型工作流:自动化的模型内部三角面剔除

1. 关于自动减面 1.1 自动减面的重要性及现状 三维模型是游戏、三维家居设计、数字孪生、VR/AR等几乎所有三维软件的核心资产&#xff0c;模型的质量和性能从根本上决定了三维软件的画面效果和渲染性能。其中&#xff0c;模型减面工作是同时关乎质量和性能这两个要素的重要工…