[译]聊聊C#中的泛型的使用

写在前面

今天忙里偷闲在浏览外文的时候看到一篇讲C#中泛型的使用的文章,因此加上本人的理解以及四级没过的英语水平斗胆给大伙进行了翻译,当然在翻译的过程中发现了一些问题,因此也进行了纠正,当然,原文的地址我放在最下面,如果你的英文水平比较好的话,可以直接直接阅读全文。同时最近建了一个.NET Core实战项目交流群637326624,有兴趣的朋友可以来相互交流。目前.NET Core实战项目之CMS的教程也已经更新了6篇了,目前两到三天更新一篇。

作者:依乐祝
原文地址:https://www.cnblogs.com/yilezhu/p/10029782.html

介绍

C#和.NET中的泛型程序具有强类型集合的许多优点,并为代码提供更高质量和性能提升。泛型是C#语言和公共语言运行库(CLR)中的一个新功能,它将类型参数的概念引入.NET Framework。类型参数使得设计某些类和方法成为可能,例如,通过使用泛型类型参数T,可以大大简化类型之间的强制转换或装箱操作的过程(装箱、拆箱问题)。说白了,泛型就是通过参数化类型来实现在同一份代码上操作多种数据类型,利用“参数化类型”将类型抽象化,从而实现灵活的复用。每个集合的详细规范可以在System.Collection.Generic名称空间下找到。

640?wx_fmt=jpeg

装箱和拆箱

.Net定义了两种主要的数据类型来表示变量,也就是传说中的值类型和引用类型。这是需要装箱和拆箱的地方。装箱是一种通过将变量存储到System.Object中来显式地将值类型转换为引用类型的机制。当您装入值时,CLR会将新对象分配到堆中,并将值类型的值复制到该实例中。例如,您创建了一个int类型的变量:

int a = 20;  object b = a; //装箱

相反的操作是拆箱,它是将引用类型转换回值类型的过程。此过程验证接收数据类型是否与装箱类型一致;

int c = (int)b; // 拆箱

C#编译器可以看到从int到object的赋值,反之亦然。当编译该程序并通过IL解析器检查IL生成的代码时,您会注意到当b被赋值为a时,程序通过在IL中自动插入一个box指令来响应,当c被赋值为b时如下;

640?wx_fmt=jpeg

代码加载常量20并将其存储在本地插槽中;它将值20加载到堆栈中并将其装箱。最后,它将被装箱的20返回到堆栈上,并将其拆箱为int类型

这个过程.NET CLR执行了一系列操作,例如,首先在托管堆中分配一个对象,然后在装箱中将值转换为内存位置,并在拆箱期间将值存储在堆上并且必须转回到堆栈。因此,从性能的角度来看,装箱和拆箱过程在泛型中具有非常重要的意义,因为这个过程如果不使用泛型的话会耗费更多地资源。

泛型类

可以通过在类名后面加上符号来定义泛型类。这里没有强制必须将“T”字放在泛型的定义中。您可以在TestClass <>类声明中使用任何单词。

public class TestClass<T> { }  

System.Collection.Generic命名空间下还定义了许多实现了这些关键字接口的类型。下表列出了此命名空间的核心类类型。

泛型类描述
Collection泛型集合的基类,可以比较两个泛型对象是否相等
Dictionary<TKey, TValue>键值对的泛型集合
List可动态调整列表项的大小
Queue先进先出(FIFO)列表的泛型实现
Stack后进先出(LIFO)列表的泛型实现

简单的泛型类示例

以下示例显示了一个简单的泛型类型的操作。TestClass 定义一个长度为5的泛型类型数组。Add()方法负责将任何类型的对象添加到集合中,而Indexer属性是循环

640?wx_fmt=png

在构建并运行该程序之后,程序的输出如下所示;

640?wx_fmt=jpeg

泛型的主要特性

泛型类型的一些重要特征使它们相比传统的非泛型类型具有如下的显著特征:

  • 类型安全

  • 性能

  • 二进制代码复用

类型安全

泛型最重要的特征之一是类型安全性。对于非泛型ArrayList类,如果使用对象类型,则可以向集合中添加任何类型,这些类型有时会导致严重的问题。下面的示例显示向ArrayList类型的集合添加一个整数、字符串和对象;

ArrayList obj = new ArrayList();  
obj.Add(50);  
obj.Add("Dog");  
obj.Add(new TestClass());  

现在,如果使用整数对象来使用foreach语句进行遍历的话,当编译器接受到代码,但是因为集合中的所有元素都不是整数,所以会导致运行时异常;

foreach(int i in obj)  
{  Console.WriteLine(i);    
}  

编程的经验法则是应该尽早检测到错误。对于泛型类Test,泛型类型T定义允许哪些类型。通过使用Test的定义,只能向集合添加整型类型的数据。这时候当Add()方法具有以下无效参数的时候编译器将不编译代码;

Test<int> obj = new Test<int>();  
obj.Add(50);  
obj.Add("Dog");            //编译错误 obj.Add(new TestClass());  //编译错误

性能

在下面的示例中,ArrayList类存储对象,并且定义了Add()方法来存储一些整型参数。因此,整数类型被装箱。当使用foreach语句读取ArrayList中的值时,将发生拆箱。

ArrayList  obj = new ArrayList();   
obj.Add(50);    //装箱- 值类型转换成引用类型 int x= (int)obj[0]; //拆箱foreach(int i in obj)  
{  Console.WriteLine(i);   // 拆箱
}

注意:泛型比其他集合(如ArrayList)更快。

代替使用对象类型,TestClass类的泛型类型被定义为int,因此在从编译器动态生成的类中将使用int类型。所以将不会发生装箱和拆箱,如下所示;

TestClass<int> obj = new TestClass<int>();  
obj.Add(50);    //没有装箱 
int x= obj[0]; // 没有拆箱
foreach(int i in obj)   {  Console.WriteLine(i);   //没有拆箱
}  

二进制代码复用

泛型类型提供了一种源代码保护机制。泛型类可以定义一次,并且可以使用许多不同类型来进行实例化。泛型可以在一种CLR支持的语言中定义,并可以被另一种.NET语言使用。以下TestClass 使用int和string类型进行实例化:

TestClass<int> obj = new TestClass<int>();  
obj.Add(50);  TestClass<string> obj1 = new TestClass<string>();  
Obj1.Add("hello");  

通用方法

虽然大多数开发人员通常会使用基类库中的现有泛型类型,但也有可能会构建自己的泛型成员和自定义的泛型类型。

本示例的目的是构建一个交换方法,该方法可以使用单个类型参数对任何可能的数据类型(基于值或基于引用)进行操作。由于交换算法的性质,传入的参数将作为使用ref关键字修饰的引用类型来进行发送。

640?wx_fmt=png

编译此泛型方法实现的程序后,输出如下所示;

640?wx_fmt=jpeg

字典

字典也被称为映射或散列表。它表示允许您基于关键字来访问元素的数据结构。字典的一个重要特征是更快的查找; 您可以添加或删除选项而不会产生性能开销。

.Net提供了几个字典类,例如Dictionary <TKey,TValue>。类型参数TKey和TValue分别表示关键字的类型和它可以存储的值。

简单的字典示例

以下示例演示使用泛型的简单字典集合。在此程序中,将创建一个Dictionary类型对象,该对象接受int作为键,字符串作为值。然后我们将一些字符串值添加到字典集合中,最后显示字典集合元素。

640?wx_fmt=png

以下示例通过定义附加类emp来描述一些更复杂的问题,其中我们覆盖ToString()方法以显示特定员工的名称和薪水。稍后在Main()方法中,创建一个新的Dictionary <TKey,TValue)的实例,其中键的类型为string,值为emp类型。构造函数分配2个元素的容量。emp对象和作为键的字符串值被添加到字典集合中。最后,使用foreach语句迭代集合元素并显示在屏幕上。

640?wx_fmt=png

队列

队列是一种特殊类型的容器,可确保以FIFO(先进先出)方式访问元素。队列集合最适合实现消息传递的组件。我们可以使用以下语法定义Queue集合对象:

Queue qObj = new Queue();

Queue集合的属性,方法和其他规则定义都位于Sysyem.Collection命名空间下。下表定义了关键成员;

System.Collection.Queue成员定义
Enqueue()将对象添加到队列的末尾。
Dequeue()从队列的开头删除对象。
Peek()返回队列开头的对象而不删除它。

下面演示了一个基本的队列类型的集合,将一些字符串类型值添加到集合中,最后使用while语句来显示整个集合中的数据 。

640?wx_fmt=png

堆栈

Stack集合是LIFO的抽象(后进先出)。我们可以使用以下语法定义Stack集合对象:

Stack qObj = new Stack();

下表说明了堆栈的关键成员;

System.Collection.Stack成员定义
Contains()如果在集合中找到特定元素,则返回true。
Clear()删除集合的所有元素。
Peek()预览堆栈中的最新元素。
Push()它将元素推入堆栈。
Pop()返回并删除堆栈的顶部元素。

以下演示了堆栈集合。首先,将数组类型对象引用到堆栈集合中。然后使用Pop()方法从堆栈中删除集合中元素的值并显示在屏幕上。

640?wx_fmt=png

在使用泛型实现的另一个示例中,使用Push()方法将5个项添加到堆栈中。然后使用循环迭代输出堆栈中的数据。堆栈的枚举器不会删除数据; 它只是以LIFO方式返回每个项目,如下所示:

640?wx_fmt=png

总结

今天忙里偷闲,在浏览外文的时候看到一篇讲泛型的文章,因此就加上自己的理解进行了相关翻译,也加深了自己对泛型的理解!如果英文比较好的话可以直接访问https://www.c-sharpcorner.com/UploadFile/84c85b/using-generics-with-C-Sharp/ 自行查看!当然,我在翻译的过程中也发现了文中的一些错误,所以进行了更正!同时最近建了一个.NET Core实战项目交流群637326624,有兴趣的朋友可以来相互交流。目前.NET Core实战项目之CMS的教程也已经更新了6篇了,目前两到三天更新一篇。最后感谢大家的阅读。

原文地址:https://www.cnblogs.com/yilezhu/p/10029782.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

640?wx_fmt=jpeg

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

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

相关文章

P5405-[CTS2019]氪金手游【树形dp,容斥,数学期望】

前言 话说在LojLojLoj下了个数据发现这题的名字叫fgofgofgo 正题 题目链接:https://www.luogu.com.cn/problem/P5405 题目大意 nnn张卡的权值为1/2/31/2/31/2/3的概率权重分别是px,1/2/3p_{x,1/2/3}px,1/2/3​&#xff0c;然后按照权值每次获得一张未获得的卡&#xff0c;然后…

模板:线段树

文章目录引言思想模板建树单点修改 / 查询区间修改/查询总结练习引言 有一类题目:要求在区间上维护信息&#xff0c;比如带修改区间求和问题。考虑到枚举求和肯定会超时&#xff0c;我们可以通过一些数据结构来维护信息&#xff0c;例如线段树。 它功能强大&#xff0c;支持区…

Docker最全教程——从理论到实战(三)

容器是应用走向云端之后必然的发展趋势&#xff0c;因此笔者非常乐于和大家分享我们这段时间对容器的理解、心得和实践。本篇教程持续编写了2个星期左右&#xff0c;只是为了大家更好地了解、理解和消化这个技术&#xff0c;能够搭上这波车。你可以关注我们的公众号“magiccode…

高并发、低延迟之C#玩转CPU高速缓存(附示例)

写在前面好久没有写博客了&#xff0c;一直在不断地探索响应式DDD&#xff0c;又get到了很多新知识&#xff0c;解惑了很多老问题&#xff0c;最近读了Martin Fowler大师一篇非常精彩的博客The LMAX Architecture&#xff0c;里面有一个术语Mechanical Sympathy&#xff0c;姑且…

RMQ问题:与众不同(st表的高端应用)

解析 预处理 用pre[i]表示以i结尾的最长完美序列起始点&#xff0c;用last[i]表示数字i最后出现的位置 那么可以得到递推式&#xff1a; pre[i]max(pre[i-1],last[x[i]]1);也就是说这个pre要么是受前一位一样的限制&#xff0c;要么是受自己的限制 用f[i]表示以i结尾的最长完…

Docker最全教程——从理论到实战(四)

容器是应用走向云端之后必然的发展趋势&#xff0c;因此笔者非常乐于和大家分享我们这段时间对容器的理解、心得和实践。本篇教程持续编写了2个星期左右并且一直在完善、补充具体的细节和实践&#xff0c;预计全部完成需要1到2个月的时间。由于编写的过程中极其费时&#xff0c…

动态规划:openjudge 2.6-3532 最大上升子序列和 解题心得

传送门 题目描述 一个数的序列bi&#xff0c;当b1 < b2 < … < bS的时候&#xff0c;我们称这个序列是上升的。对于给定的一个序列(a1, a2, …,aN)&#xff0c;我们可以得到一些上升的子序列(ai1, ai2, …, aiK)&#xff0c;这里1 < i1 < i2 < … < iK…

边缘化搭建 DotNet Core 2.1 自动化发布和部署(下)

写在前面本篇文章是上一篇边缘化搭建 DotNet Core 2.1 自动化发布和部署(上)的后续操作&#xff0c;本文主要讲解如何开启Docker Remote API&#xff0c;开启Remote API后的权限安全问题。配置Jenkins构建项目&#xff0c;并在云服务器上构建成功。废话不多说&#xff0c;我们一…

边缘化搭建DotNet Core 2.1 自动化构建和部署环境(上)

写在前面写这篇文章的缘由是由于笔者的对新兴技术方向有所追求&#xff0c;但个人资产有限&#xff0c;只能容许购买一台阿里云低配1核2G服务器。服务器上搭建了 Centos7 & Docker & Jenkins & ASP.NET Core 2.0 自动化发布和部署 环境后牺牲了大部分性能。造成了一…

.NET Core实战项目之CMS 第六章 入门篇-Vue的快速入门及其使用

写在前面上面文章我给大家介绍了Dapper这个ORM框架的简单使用&#xff0c;大伙会用了嘛&#xff01;本来今天这篇文章是要讲Vue的快速入门的&#xff0c;原因是想在后面的文章中使用Vue进行这个CMS系统的后台管理界面的实现。但是奈何Vue实现的SPA有一定的门槛&#xff0c;不太…

不止代码:ybtoj-棋盘分割(二维区间dp)

题目描述 将一个8*8的棋盘进行如下分割&#xff1a;将原棋盘割下一块矩形棋盘并使剩下部分也是矩形&#xff0c;再将剩下的部分继续如此分割&#xff0c;这样割了n-1次后&#xff0c;连同最后剩下的矩形棋盘共有n块矩形棋盘。 (每次切割都只能沿着棋盘格子的边进行) 原棋盘上…

通俗易懂,C#如何安全、高效地玩转任何种类的内存之Span

前言作为.net程序员&#xff0c;使用过指针&#xff0c;写过不安全代码吗&#xff1f;为什么要使用指针&#xff0c;什么时候需要使用它&#xff1f;如果能很好地回答这两个问题&#xff0c;那么就能很好地理解今天了主题了。C#构建了一个托管世界&#xff0c;在这个世界里&…

AC自动机:例题与机制详解

介绍 AC自动机是kmp算法和trie树的结合 大体就是做这样的题用&#xff1a; 可以发现&#xff0c;这题和trie树的区别是把多个单词往一篇文章匹配&#xff0c;而trie恰好相反 匹配的时候其实就是判断子串&#xff0c;所以又用到了kmp 定义失配指针nxt[i]&#xff1a;表示root到…

.NET Core实战项目之CMS 第七章 设计篇-用户权限极简设计全过程

写在前面这篇我们对用户权限进行极简设计并保留其扩展性。首先很感谢大家的阅读&#xff0c;前面六章我带着大家快速入门了ASP.NET Core、ASP.NET Core的启动过程源码解析及配置文件的加载过程源码解析并引入依赖注入的概念、Git的快速入门、Dapper的快速入门、Vue的快速入门。…

2021“MINIEYE杯”中国大学生算法设计超级联赛(5)Random Walk 2(推式子+矩阵逆+矩阵乘)

Random Walk 2 【2.4】Gauss-Jordan消元法求矩阵的逆 高斯消元求矩阵的逆&#xff0c;伴随单位矩阵一起消元即可。 [A,I]→[I,A−1][\text A,\text I]\to [\text I,\text A^{-1}][A,I]→[I,A−1] 移项变形&#xff0c;后就是个矩阵的逆&#xff0c;为啥赛时不写&#xff1f;&a…

参加胶东开发者技术大会有感

2015年的时候&#xff0c;也是在12月&#xff0c;我和Bob(https://www.cnblogs.com/nianming/)去北京参加了“全球架构师峰会”&#xff0c;在那次会议上&#xff0c;来自百度、腾讯、阿里巴巴、京东、美团、新浪微博、Twitter等公司的架构师、技术专家们分享了各自在架构方面的…

专题:数列信息传递问题转化为图论合点问题(ybtoj-数列询问+序列破解)

文章目录前言&#xff1a;一、数列询问&#xff08;取模&#xff09;解析代码二、序列破解&#xff08;奇偶性&#xff09;解析代码thanks for reading&#xff01;前言&#xff1a; 在一个数列a中&#xff0c;对于一个大区间A和组成它的两个小区间a&#xff0c;b&#xff1b;…

Docker最全教程——从理论到实战(五)

在笔者参加腾讯容器服务技术交流会时&#xff0c;我们了解到了藏区牧民的目前的生活艰辛状况&#xff0c;因此除了在同事朋友之间推荐其土特产之外&#xff0c;我们也在此进行初步分享&#xff0c;希望略尽绵薄之力&#xff0c;能够帮助到他们&#xff1a;货真价实、确保都是37…

2021牛客暑期多校训练营6 J-Defend Your Country(无向图点双+思维)

无向图联通分量 点u是割点&#xff0c;当且仅当 特判树根&#xff1a;u为树根&#xff0c;且u有多于1棵子树u不为树根&#xff0c;在递归树上u存在子节点v&#xff0c;满足&#xff1a;dfnu≤lowv\text{dfn}_u\leq \text{low}_vdfnu​≤lowv​ 如上图&#xff0c;v想走到u的组…

不止代码:循环比赛(分治)

循环比赛日程表&#xff08;match&#xff09; 【问题描述】 解析 dfs或分治 分治可以不断递归4个小正方形 左上右下为前一半&#xff0c;左下右上后一半 dfs就很无脑了 代码 #include<cstdio> #include<cstring> #include<algorithm> #include<cmath…