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引用替换类型参数来创建一个具体的泛型类型(而不是基于所提供的类型实参)。以后,每次引用类型参数实例化一个构造好的类型,”运行时“都重用之前生成好的泛型类型的版本–即使提供的引用类型与第一次不同。
相关文章:
C#8.0本质论第十二章--泛型
C#8.0本质论第十二章–泛型 C#通过泛型来促进代码重用,在词义上等价于C模板。 在泛型编程中,数据类型也是一种参数。 12.1如果C#没有泛型 为object的方法使用值类型时,“运行时”将自动对它进行装箱,获取值类型的实例时则需要…...
Python与ArcGIS系列(七)自动化打印地图
目录 0 简述1 获取可用打印机列表2 打印地图3 导出地图至PDF4 导出地图至图像0 简述 本篇介绍如何利用arcpy实现获取可用打印机列表、打印地图、导出地图至PDF和图像。 1 获取可用打印机列表 通过arcpy提供的ListPrinterNames()函数可以生成可用的打印机列表。 import arcpy.m…...

基于STM32单片机抢答器设计
**单片机设计介绍, 基于STM32单片机抢答器设计-Proteus仿真 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于STM32单片机的抢答器设计可以用于教育和培训场景中的抢答游戏或考试环节。以下是一个基本的介绍设计步骤…...

冯·诺伊曼体系结构--操作系统
文章目录 1.认识冯诺依曼系统1.1约翰冯诺依曼1.2冯诺依曼结构1.3存储器的读写速度1.4对冯诺依曼结构的认识1.5冯诺依曼结构在生活中的演示 2.操作系统--“搞管理”的软件2.1概念2.2OS存在的意义2.3管理的方式2.4系统调用和库函数概念 1.认识冯诺依曼系统 1.1约翰冯诺依曼 1.2冯…...
IDEA插件开发--持久化配置信息方案
这里写自定义目录标题 配置信息持久化存储保存配置文件的方式每种方式的实现方案1.PropertiesComponent:2.PersistentStateComponent:3.Project Settings:4.外部文件: 5.数据库:6.加密数据:7,自定义配置文件…...

Vscode禁止插件自动更新
由于电脑的vscode版本不是很新。2022.10月份的版本1.7.2,电脑vscode的python插件装的也是2022年4月份的某个版本,但插件经常自动更新,导致python代码无法Debug,解决办法: 点设置,搜autoUpdate, 把红色框选成无...
Zookeeper篇---第六篇
系列文章目录 文章目录 系列文章目录一、请简述Zookeeper的选主流程二、为什么Zookeeper集群的数目,一般为奇数个?三、知道Zookeeper监听器的原理吗?一、请简述Zookeeper的选主流程 Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做…...
mysql数据库存储过程之游标(光标cursor)
游标是用来存储查询结果集的数据类型,在存储过程和函数中可以使用游标对结果集进行循环的处理。游标的使用包括游标的声明、open、fetch和close。 一、语法。 #声明游标 declare 游标名称 cursor for 查询语句; #开启游标 open 游标名称; #获取游标记录 fetch 游标…...

「帝国风暴兵」加入 The Sandbox,推出真实的全新人物化身系列和体验!
我们很高兴宣布与流行文化中最具标志性的娱乐品牌 Shepperton 设计工作室的「帝国风暴兵」达成合作伙伴关系。这一合作标志着该科幻品牌首次进入元宇宙,让风暴兵的粉丝们以全新的方式体验「帝国风暴兵」。 在这个体验中,玩家将置身于帝国风暴兵的营地&am…...

asp.net员工管理系统VS开发sqlserver数据库web结构c#编程包括出差、请假、考勤
一、源码特点 asp.net员工管理系统是一套完善的web设计管理系统(主要包括出差、请假、考勤基础业务管理),系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为vs2010 ,数据库为sqlserver2008&a…...

C++套接字库sockpp介绍
sockpp是一个开源、简单、现代的C套接字库,地址为:https://github.com/fpagliughi/sockpp,最新发布版本为0.8.1,license为BSD-3-Clause。目前支持Linux、Windows、Mac上的IPv4、IPv6和Unix域套接字。其它*nix和POSIX系统只需很少的…...
Mac M2开发环境安装
持续更新 brew 安装 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"JAVA多版本环境 ## 终端下载安装 brew install --cask temurin8 brew install --cask temurin11 brew install --cask temurin17## vim ~/.…...

Linux各种版本安装详细步骤和root密码破解
文章目录 VMware新建虚拟机硬件设置设置虚拟网络挂载ISO文件 root密码破解 VMware新建虚拟机 硬件设置 设置虚拟网络 编辑>虚拟网络编辑器>VMnet8(NAT模式) 挂载ISO文件 加电>开启次虚拟机 第二项可以检查挂载上来的iso文件是否完整没有破坏 磁盘分区 选自定义分…...

Netty - 回顾Netty高性能原理和框架架构解析
文章目录 概述JDK 原生 NIO 程序的问题Why Netty使用场景Related ProjectsNetty 高性能设计I/O 模型【阻塞 I/O】:【I/O 复用模型】【基于 Buffer】 线程模型事件驱动模型Reactor 线程模型Netty的线程模型异步处理 Netty框架的架构设计功能特性模块组件Bootstrap、S…...

uni-app——項目day01
配置uni-app開發環境 uni-app快速上手 | uni-app官网 创建项目 图中四个划线就是要配置的地方. 选择vue2还是vue3看个人选择。 目录结构 但是现在新版本创建的项目已经没有components目录了,需要自己创建。 项目运行到微信开发者工具 使用git管理项目 node-mod…...
【Java、MongoDB】程序控制非关系数据库
步骤: (1)连接 连接字符串 (2)CRUD 类与接口 解析 (3)maven管理方法 依赖 <dependency><groupId>org.mongodb</groupId><artifactId>mongodb-driver-legacy<…...

MySQL查询时间处理相关函数与方法实践笔记
1. 实践案例 在查询mysql数据库获取数据时,有这样一个需求:按每30分钟分组获取电量数据,形成1天48个数据点。 方法一: select hour(a.CreateTime) 时点,case when MINUTE(a.CreateTime)<30 then 1 else 2 end 半小时,sum(a…...

springboot全局拦截sql异常
起因:非法用户可通过特定的输入(如输入内容超长)等操作,使后台逻辑发生错误,从而使后台sql语句暴露至前台,进而为sql攻击提供条件 处理流程:经查找com.mysql.cj.jdbc.exceptions的父类为SQLException,在全局异常处理类中增加如下配置,经测试不起作用 ExceptionHandler(SQLExce…...

AlGaN/GaN HFET 五参数模型
标题:A Five-Parameter Model of the AlGaN/GaN HFET 来源:IEEE TRANSACTIONS ON ELECTRON DEVICES(15年) 摘要—我们引入了AlGaN/GaN异质结场效应晶体管(HFET)漏极电流Id(Vgs,Vds…...

矩阵的除法
B/A 如果矩阵A可逆,那么 证明: A/AB 如果矩阵A和B都可逆,那么 证明:...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...

算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...

【分享】推荐一些办公小工具
1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由:大部分的转换软件需要收费,要么功能不齐全,而开会员又用不了几次浪费钱,借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...

Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...

android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...