windows C#-运行时泛型

server/2025/1/14 1:12:29/
C++ 模板和 C# 泛型之间的区别

C# 泛型和 C++ 模板均是支持参数化类型的语言功能。 但是,两者之间存在很多不同。 在语法层次,C# 泛型是参数化类型的一个更简单的方法,而不具有 C++ 模板的复杂性。 此外,C# 不试图提供 C++ 模板所具有的所有功能。 在实现层次,主要区别在于 C# 泛型类型的替换在运行时执行,从而为实例化对象保留了泛型类型信息。 

以下是 C# 泛型和 C++ 模板之间的主要差异:

  • C# 泛型的灵活性与 C++ 模板不同。 例如,虽然可以调用 C# 泛型类中的用户定义的运算符,但是无法调用算术运算符。
  • C# 不允许使用非类型模板参数,如 template C<int i> {}。
  • C# 不支持显式定制化;即特定类型模板的自定义实现。
  • C# 不支持部分定制化:部分类型参数的自定义实现。
  • C# 不允许将类型参数用作泛型类型的基类。
  • C# 不允许类型参数具有默认类型。
  • 在 C# 中,泛型类型参数本身不能是泛型,但是构造类型可以用作泛型。 C++ 允许使用模板参数。
  • C++ 允许在模板中使用可能并非对所有类型参数有效的代码,随后针对用作类型参数的特定类型检查此代码。 C# 要求类中编写的代码可处理满足约束的任何类型。 例如,在 C++ 中可以编写一个函数,此函数对类型参数的对象使用算术运算符 + 和 -,在实例化具有不支持这些运算符的类型的模板时,此函数将产生错误。 C# 不允许此操作;唯一允许的语言构造是可以从约束中推断出来的构造。
运行时中的泛型 

泛型类型或方法编译为公共中间语言 (CIL) 时,它包含将其标识为具有类型参数的元数据。 如何使用泛型类型的 CIL 根据所提供的类型参数是值类型还是引用类型而有所不同。

使用值类型作为参数首次构造泛型类型时,运行时创建专用的泛型类型,CIL 内的适当位置替换提供的一个或多个参数。 为每个用作参数的唯一值类型一次创建专用化泛型类型。

例如,假定程序代码声明了一个由整数构造的堆栈:

Stack<int>? stack;

此时,运行时生成一个专用版 Stack<T> 类,其中用整数相应地替换其参数。 现在,每当程序代码使用整数堆栈时,运行时都重新使用已生成的专用 Stack<T> 类。 在下面的示例中创建了两个整数堆栈实例,且它们共用 Stack<int> 代码的一个实例: 

Stack<int> stackOne = new Stack<int>();
Stack<int> stackTwo = new Stack<int>();

但是,假定在代码中另一点上再创建一个将不同值类型(例如 long 或用户定义结构)作为参数的 Stack<T> 类。 其结果是,运行时在 CIL 中生成另一个版本的泛型类型并在适当位置替换 long。 转换已不再必要,因为每个专用化泛型类本机包含值类型。

对于引用类型,泛型的作用方式略有不同。 首次使用任意引用类型构造泛型类型时,运行时创建一个专用化泛型类型,用对象引用替换 CIL 中的参数。 之后,每次使用引用类型作为参数实例化已构造的类型时,无论何种类型,运行时皆重新使用先前创建的专用版泛型类型。 原因可能在于所有引用大小相同。

例如,假定有两个引用类型、一个 Customer 类和一个 Order 类,并假定已创建 Customer 类型的堆栈:

class Customer { }
class Order { }Stack<Customer> customers;

此时,运行时生成一个专用版 Stack<T> 类,此类存储之后会被填写的引用类型,而不是存储数据。 假定下一行代码创建另一引用类型的堆栈,其名为 Order:

Stack<Order> orders = new Stack<Order>();

不同于值类型,不会为 Order 类型创建 Stack<T> 类的另一专用版。 相反,创建专用版 Stack<T> 类的实例并将 orders 变量设置为引用此实例。 假定之后遇到一行创建 Customer 类型堆栈的代码:

customers = new Stack<Customer>();

与之前使用通过 Order 类型创建的 Stack<T> 类一样,会创建专用 Stack<T> 类的另一个实例。 其中包含的指针设置为引用 Customer 类型大小的内存区。 由于引用类型的数量因程序不同而有较大差异,因此通过将编译器为引用类型的泛型类创建的专用类的数量减少至 1,泛型的 C# 实现可极大减少代码量。

此外,使用值类型或引用类型参数实例化泛型 C# 类时,反射可在运行时对其进行查询,且其实际类型和类型参数皆可被确定。


http://www.ppmy.cn/server/158140.html

相关文章

超燃预告!Origin百图绘制系列即将登场

Hello&#xff0c;大家好 这里是练习时长两年半的菜狗~ 持续更新各种竞赛&#xff0c;科研&#xff0c;保研&#xff0c;学习干货ing 回想刚开始打比赛那会&#xff0c;啥都不懂&#xff0c;就从用 Excel 画图起步&#xff0c;绘制的图形实在太难看。后来运用 Matlab&#xf…

初学stm32 --- DAC输出三角波和正弦波

输出三角波实验简要&#xff1a; 1&#xff0c;功能描述 通过DAC1通道1(PA4)输出三角波&#xff0c;然后通过DS100示波器查看波形 2&#xff0c;关闭通道1触发(即自动) TEN1位置0 3&#xff0c;关闭输出缓冲 BOFF1位置1 4&#xff0c;使用12位右对齐模式 将数字量写入DAC_…

最近在盘gitlab.0.先review了一下docker

# 正文 本猿所在产品的代码是保存到了一个本地gitlab实例上&#xff0c;实例是别的同事搭建的。最近又又又想了解一下&#xff0c;而且已经盘了一些了&#xff0c;所以写写记录一下。因为这个事儿没太多的进度压力&#xff0c;索性写到哪儿算哪儿&#xff0c;只要是新了解到的…

核磁机器学习 | 机器学习和深度学习算法在fMRI中的应用

摘要 功能磁共振成像(fMRI)是目前应用最广泛的脑图像动态分析技术之一&#xff0c;通常结合多种算法来分析复杂的动态数据。近年来&#xff0c;机器学习和深度学习算法在分析fMRI数据方面的应用呈指数级增长。然而&#xff0c;由于文献中存在大量算法&#xff0c;选择合适的机器…

C语言初阶习题【23】输出数组的前5项之和

1. 题目描述 求Snaaaaaaaaaaaaaaa的前5项之和&#xff0c;其中a是一个数字&#xff0c; 例如&#xff1a;222222222222222 2.思路 分析下&#xff0c;222222222222222&#xff0c;怎么把它每一项算出来 2 210222 22102222 2221022222 我们的多项式就是a a*102&#xff0c;…

云端 IPv4 VRRP+MSTP多备份组配置实验

SW3和SW4作为核心交换机&#xff0c;SW1和SW2分别有两条链路可做冗余链路连接到核心交换机上。 1、把SW3和SW4配置vrrp虚拟路由器冗余协议&#xff0c;把两台路由器虚拟成一台路由器 2、创建两个备份组&#xff0c;备份组一的虚拟ip做pc6的网关&#xff0c;备份组二的虚拟ip做…

mysql,PostgreSQL,Oracle数据库sql的细微差异(2) [whith as; group by; 日期引用]

sql示例(MySQL) WITHtemp1 AS (SELECT name AS resultsFROM Users uJOIN MovieRating m ON u.user_id m.user_idGROUP BY m.user_idORDER BY COUNT(*) DESC,left(name,1)LIMIT 1),temp2 AS (SELECT title AS resultsFROM Movies mJOIN MovieRating r ON m.movie_id r.movie_…

【Linux】【进程】进程和线程

【Linux】【进程】进程和线程 在Linux操作系统中 内核对进程和线程均是通过task_struct结构体&#xff08;也就是所谓的pcb&#xff09;来管理的 task_struct&#xff08;存储在内核空间由内核直接控制和管理 用户空间无法直接访问 通过双向链表管理&#xff09; 结构体里面有…