C#8.0本质论第十二章--泛型

C#8.0本质论第十二章–泛型

C#通过泛型来促进代码重用,在词义上等价于C++模板。

在泛型编程中,数据类型也是一种参数。

12.1如果C#没有泛型

为object的方法使用值类型时,“运行时”将自动对它进行装箱,获取值类型的实例时则需要显式拆箱。

12.2捕捉异常

C#的设计者采用了与C++模板相似的语法。所以C#泛型类和结构要求开发者声明泛型类型参数以及提供泛型类型实参

12.2.1使用泛型类
12.2.2定义简单泛型类
12.2.3泛型的优点

泛型促进了类型安全

编译时类型检查减少了在运行时发生InvalidCastException异常的概率

为泛型类成员使用值类型,不再造成到object的装箱转换。

C#泛型缓解了代码膨胀

性能得以提升.

内存消耗减少,由于避免了装箱,因此减少了在堆上的内存消耗。

代码可读性更好。

12.2.4类型参数命名规范

为了强调类型参数,名称应包含T前缀。

12.2.5泛型接口和结构
12.2.6定义构造函数和终结器

泛型类或结构的构造函数(和终结器)不要求类型参数。

12.2.7用default操作符指定默认值

假定有一个结构体类型Pair的构造函数,实例化时只对数的一半进行初始化,字段Second处于未初始化的状态,会造成编译错误,我们无法给Second设置初始值,因为在编写构造函数时还不知道它的类型T具体是什么。

为应对这样的局面,C#提供了default操作符。

public struct Pair<T> : IPair<T>
{public Pair(T first){First = first;Second = default;// ...}
}

12.2.8多个类型参数

类型参数的数量(或称为元数,即arity)区分了同名类,仅元数不同的泛型应放到同一个C#文件中。

方法可以通过“参数数组”获取任意数量的实参,但泛型类型不可以。每个泛型类型的元数都必须固定。

12.2.9嵌套泛型类型

避免在嵌套类型中用同名参数隐藏外层类型的类型参数。

12.3约束

为避免异常,而是生成编译时的错误,C#允许为泛型类中声明的每个类型参数提供可选的约束列表。需要使用where关键字,后跟一对“参数:要求”

12.3.1接口约束

规定某个数据类型必须实现某个接口。

12.3.2类型参数约束

有时要求将类型实参转换为特定的类型。

假如同时指定了多个约束,那么类类型约束必须第一个出现。和接口约束不同的是不允许多个类类型约束。

12.3.3非托管约束

从C#8.0开始,结构也可以是泛型的。

12.3.4非空约束

notnull即非空约束,不能和struct和class约束共用。

12.3.5struct/class约束

将类型参数限制为任何非可空值类型或任何引用类型。

12.3.6多个约束

如果有多个类型参数,每个类型参数前面都要使用where关键字。两个where子句之间并不存在逗号。

public class EntityDictionary<TKey, TValue>: System.Collections.Generic.Dictionary<TKey, TValue>where TKey : notnullwhere TValue : EntityBase
{// ...
}
12.3.7构造函数约束

并非所有对象都肯定有公共默认构造函数,所以编译器不允许为未约束的类型参数调用默认构造函数。要在其他所有约束之后添加new()。只能对默认构造函数进行约束。

12.3.8约束继承

无论泛型类型参数,还是它们的约束,都不会被派生类继承,因为泛型类型参数不是成员。

12.4泛型方法

12.4.1泛型方法类型推断

未避免多余的编码,当编译器可以逻辑推断出想要的类型参数时,调用时可以不指定类型实参。这称为方法类型推断

12.4.2指定约束

12.5协变性和逆变性

刚接触泛型类型的人经常问一个问题:为什么不能将List类型的表达式赋给List类型的变量。既然string能转换成object,string列表应该也应兼容于object列表呀?实际情况并非如此,这个赋值动作既不类型安全,也不合法。因为他们不是协变量(covariant).

“协变量”借鉴自范畴论的术语。假定两个类型X和Y具有特殊关系,即每个X类型的值都能转换成Y类型.

使用仅一个参数的泛型类型时,可以简单地说“I是协变的”,从I想I的转换称为协变转换

为什么不合法:

// ...
// Error: Cannot convert type ...
Pair<PdaItem> pair = (Pair<PdaItem>)new Pair<Contact>();
IPair<PdaItem> duple = (IPair<PdaItem>)new Pair<Contact>();
// ...
Contact contact1 = new("Princess Buttercup");
Contact contact2 = new("Inigo Montoya");
Pair<Contact> contacts = new(contact1, contact2);// This gives an error: Cannot convert type ...
// But suppose it did not
IPair<PdaItem> pdaPair = (IPair<PdaItem>) contacts;
// This is perfectly legal, but not type-safe
pdaPair.First = new Address("123 Sesame Street");

先在应该很清楚为什么字符串列表不能作为对象列表使用了。在字符串列表中不能插入整数,但在对象列表中可以。

12.5.1使用out类型参数修饰符允许协变性

从C#4开始加入了对安全协变性的支持。要指出泛型接口应该对它的某个类型参数协变,就用out修饰符来修饰改类型参数。

用out修饰IReadOnlyPair接口的类型参数,会导致编译器验证T是否真的只用作“输出”,且永远不用于形参或属性的赋值方法。

协变转换有一些重要限制:

只有泛型接口和泛型委托才能协变。泛型类和结构永远不是协变的。

提供给“来源”和“目标”泛型类型的类型实参必须是引用类型,不能是值类型。

接口或委托必须声明为支持协变,编译器必须验证协变所针对的类型参数确实只用在“输出”位置。

12.5.2使用in类型参数修饰符允许协变性

协变性的反方向称为逆变性(contravariance)。假定X和Y类型彼此相关,每个X类型的值都能转换成Y类型。如果I和I类型总是具有相反的特殊关系–也就是说I类型的每个值都能转换成I类型–就说“I对T逆变”。

12.5.3数组对不安全协变性的支持

12.6泛型的内部机制

事实上,泛型类的“类型参数”成了元数据,“运行时“在需要时会利用它们构造恰当的类。为避免装箱,对于基于值的类型参数,其泛型实现和引用类型参数的泛型实现是不同的。

用值类型作为类型参数首次构造一个泛型类型时,”运行时“会将指定的类型参数放到CIL中合适的位置,从而创建一个具体化的泛型类型。每当代码用到时,都重用已经生成的具体化的类。

对于引用类型,泛型的工作方式稍有不同。使用引用类型作为类型参数首次构造一个泛型类型时,”运行时“会在CIL代码中用object引用替换类型参数来创建一个具体的泛型类型(而不是基于所提供的类型实参)。以后,每次引用类型参数实例化一个构造好的类型,”运行时“都重用之前生成好的泛型类型的版本–即使提供的引用类型与第一次不同。

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

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

相关文章

树莓派4B的测试记录(CPU、FFMPEG)

本文是用来记录树莓派 4B 的一些测试记录。 温度 下面记录中的风扇和大风扇是这样的&#xff1a; 为什么要用大风扇呢&#xff1f;因为小风扇在外壳上&#xff0c;气流通过外壳的珊格会有啸叫&#xff0c;声音不大但是很烦人&#xff0c;大风扇没这个问题&#xff0c;并且同样…

Vue3 数据响应式原理:Proxy和Reflect

我们在Vue2中使用的是Object.defineProperty方法来实现数据响应式的&#xff0c;可以通过get和set方法来监听对象的访问和修改。 但是并不能响应对象中属性的增加和删除&#xff0c;只能使用Vue.$set 和Vue.$delete 来对对象中的属性进行增加和删除。 数组也不能直接通过下标…

PyCharm因安装了illuminated Cloud插件导致加载项目失败

打开Pycharm时会有弹窗提示&#xff1a; The license for Illuminated Cloud is invalid or has expired. All Illuminated Cloud features will be disabled. 这个弹窗会导致你加载项目一直失败&#xff0c;close project 也关不掉&#xff0c;我都是用任务管理器杀死进程的…

Jmeter 性能 —— 负载阶梯场景!

1、安装阶梯测试的第三方插件->搜jpgc 选项-JMeter Plugins Manager -搜jpgc 空格&#xff0c;然后安装 2、脚本-线程组选jpgc Stepping Thread Group 最终并发数为100&#xff0c;并发数从0开始&#xff0c;5秒内增加10个并发数&#xff0c;增加10个后持续30s&#xff0c;…

学习c#的第十天

目录 C# 字符串&#xff08;String&#xff09; 创建 String 对象 String 类的属性 String 类的方法 实例 C#的string.Format格式化日期 C# 字符串&#xff08;String&#xff09; 创建 String 对象 可以使用以下方法之一来创建 string 对象&#xff1a; 1、通过给 St…

taro(踩坑) npm run dev:weapp 微信小程序开发者工具预览报错

控制台报错信息&#xff1a; VM72:9 app.js错误: Error: module vendors-node_modules_taro_weapp_prebundle_chunk-JUEIR267_js.js is not defined, require args is ./vendors-node_modules_taro_weapp_prebundle_chunk-JUEIR267_js.js 环境&#xff1a; node 版本&#x…

Spring Boot(二)

1、运行维护 1.1、打包程序 SpringBoot程序是基于Maven创建的&#xff0c;在Maven中提供有打包的指令&#xff0c;叫做package。本操作可以在Idea环境下执行。 mvn package 打包后会产生一个与工程名类似的jar文件&#xff0c;其名称是由模块名版本号.jar组成的。 1.2、程序…

vue分片上传视频并转换为m3u8文件并播放

开发环境&#xff1a; 基于若依开源框架的前后端分离版本的实践&#xff0c;后端java的springboot&#xff0c;前端若依的vue2&#xff0c;做一个分片上传视频并分段播放的功能&#xff0c;因为是小项目&#xff0c;并没有专门准备文件服务器和CDN服务&#xff0c;后端也是套用…

2023NewStarCTF

目录 一、阳光开朗大男孩 二、大怨种 三、2-分析 四、键盘侠 五、滴滴滴 六、Include? 七、medium_sql 八、POP Gadget 九、OtenkiGirl 一、阳光开朗大男孩 1.题目给出了secret.txt和flag.txt两个文件&#xff0c;secret.txt内容如下&#xff1a; 法治自由公正爱国…

【Redis】list常用命令内部编码使用场景

文章目录 前置知识列表类型的特点 命令LPUSHLPUSHXRPUSHRPUSHXLRANGELPOPRPOPLINDEXLREMLINSERTLTRIMLSETLLEN 阻塞版本命令BLPOPBRPOP 命令总结内部编码测试内部编码 使用场景消息队列分频道的消息队列 模拟栈和队列 前置知识 列表类型是⽤来存储多个有序的字符串&#xff0c…

第一次实操Python+robotframework接口自动化测试

目前我们需要考虑的是如何实现关键字驱动实现接口自动化输出&#xff0c;通过关键字的封装实现一定意义上的脚本与用例的脱离&#xff01; robot framework 的安装不过多说明&#xff0c;网上资料比较太多~ 实例&#xff1a;&#xff01;&#xff01;&#xff01;&#xff01…

AI:80-基于深度学习的医学图像分割与病变识别

🚀 本文选自专栏:人工智能领域200例教程专栏 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带有在本地跑过的代码,详细讲解供大家学习,希望可以帮到大家。欢迎订阅支持,正在不断更新中,…

day55 反向解析和视图层精确定位

上周内容回顾 orm的增删改查 1. 查询 from app01 import models models.UserInfo.objects.all() # 查询所有的字段信息和数据 resmodels.UserInfo.objects.first() # 查询一条&#xff0c;而且是第一条&#xff0c;queryset对象&#xff0c;列表套对象的形式 if res:res[0] t…

【表面重建】第一篇:delaunay三角化(未完)

文章目录 声明delaunay三角片的特性实现delaunay算法的分类生长算法逐点插入算法分治算法基于Bowyer-Watson算法 code调用scipy的API调用cgal的API 参考来源 声明 本帖持续更新中最近一次更新日期&#xff1a;2023.11.13如有纰漏望指正&#xff01; delaunay三角片的特性 de…

Flink SQL 表值聚合函数(Table Aggregate Function)详解

使用场景&#xff1a; 表值聚合函数即 UDTAF&#xff0c;这个函数⽬前只能在 Table API 中使⽤&#xff0c;不能在 SQL API 中使⽤。 函数功能&#xff1a; 在 SQL 表达式中&#xff0c;如果想对数据先分组再进⾏聚合取值&#xff1a; select max(xxx) from source_table gr…

2022年06月 Python(五级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试(1~6级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 Python中 print(“八进制{: o}”.format(12)) 正确的输出结果是?( ) A: 八进制:O B: 八进制:O14 C: 八进制14O D: 八进制14 答案:D 字符串的format()格式。 第2题 下列的程…

PostgreSQL基础入门

为什么选择PostgreSQL 功能更全面&#xff1a;PGSQL的功能更加全面&#xff0c;支持开窗函数、物化视图、分区表、json等类型&#xff0c;MySQL8以上支持开窗函数、分区表、json等&#xff0c;但物化视图仍不支持。高可用&#xff1a;PG更适合分布式环境&#xff0c;如流复制、…

pychon/PIL/opencv/json学习过程中遇到的问题

1. 使用PIL.Image读取图片 注意&#xff1a;pytorch中对图像预处理是transforms的输入必须是PIL格式的文件&#xff0c;使用cv2读取的图片就按照第二条的代码处理&#xff08;3通道合并、归一化处理&#xff09; from PIL import Image img Image.open("test1.jpg"…

TensorFlow: An open-source software library for Machine Intelligence

Google开源的机器学习软件包 项目主页:https://www.tensorflow.org/Github主页:GitHub - tensorflow/tensorflow: An Open Source Machine Learning Framework for Everyone主要版本:1.0(当前最新版本),0.12.0开源协议:Apache 2.0TensorFlow™ 是一个采用数据流图(data…

2023 年最新企业微信官方会话机器人开发详细教程(更新中)

目标是开发一个简易机器人&#xff0c;能接收消息并作出回复。 获取企业 ID 企业信息页面链接地址&#xff1a;https://work.weixin.qq.com/wework_admin/frame#profile 自建企业微信机器人 配置机器人应用详情 功能配置 接收消息服务器配置 配置消息服务器配置 配置环境变量…