[译]聊聊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,一经查实,立即删除!

相关文章

牛客题霸 [ 最长递增子序列] C++题解/答案

牛客题霸 [ 最长递增子序列] C题解/答案 题目描述 给定数组arr&#xff0c;设长度为n&#xff0c;输出arr的最长递增子序列。&#xff08;如果有多个答案&#xff0c;请输出其中字典序最小的&#xff09; 题意&#xff1a; 直接暴力会超时 应该用二分贪心 题解&#xff1a…

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…

2021牛客暑期多校训练营4 H-Convolution(数学)

H-Convolution x⨂yxygcd⁡(x,y)x\bigotimes y\frac{xy}{\gcd(x,y)}x⨂ygcd(x,y)xy​ 下面大佬题解推&#x1f981; Ultraman-Ace题解 #include<bits/stdc.h> using namespace std; using lllong long; template <class Tint> T rd() {T res0;T fg1;char chgetcha…

牛客题霸 [ 排序] C++题解/答案

题目描述 给定一个数组&#xff0c;请你编写一个函数&#xff0c;返回该数组排序后的形式。 题意&#xff1a; 排序的方式有很多 二分呀&#xff0c;桶排呀归并等等 stl里的sort快速排序方便好用 题解&#xff1a; class Solution { public:/*** 代码中的类名、方法名、参…

ARC106E-Medals【hall定理,高维前缀和】

正题 题目链接:https://atcoder.jp/contests/arc106/tasks/arc106_e 题目大意 nnn个员工&#xff0c;第iii个在[1,Ai][1,A_i][1,Ai​]工作&#xff0c;[Ai1,2Ai][A_i1,2\times A_{i}][Ai​1,2Ai​]休息&#xff0c;[2Ai1,3Ai][2\times A_i1,3\times A_i][2Ai​1,3Ai​]工作…以…

高并发、低延迟之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结尾的最长完…

codeforces1554 E. You(思维+数学+转化)

E. You 首先我们假设每个节点有个点权&#xff0c;点权是儿子的数量。 一个点可以和他的父亲所要权值1&#xff08;先删去自己&#xff0c;再删去父亲&#xff09;&#xff0c;并且此操作不可逆。于是dfs从叶子节点一次递推即可得出某个kkk是否能作为gcd⁡\gcdgcd。 由于上述…

牛客题霸 [括号生成] C++题解/答案

牛客题霸 [括号生成] C题解/答案 题意&#xff1a; 给出n对括号&#xff0c;请编写一个函数来生成所有的由n对括号组成的合法组合。 例如&#xff0c;给出n3&#xff0c;解集为&#xff1a; “((()))”, “(()())”, “(())()”, “()()()”, “()(())”, 题解&#xff1a; …

P5404-[CTS2019]重复【KMP,dp】

正题 题目链接:https://www.luogu.com.cn/problem/P5404 题目大意 给出一个字符串SSS&#xff0c;然后求有多少个长度为mmm的串TTT满足。无限多个串TTT拼接起来后能找出一个长度和SSS相等的子串字典序比SSS小。 1≤∣S∣,m≤20001\leq |S|,m\leq 20001≤∣S∣,m≤2000 解题思…

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

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

模板:高精

想必大家一定都深受高精所害 python党&#xff1a;啥叫高精&#xff1f; 这里送上一种高精板子 写法 转载自巨神wyx的博客 #include <bits/stdc.h> using namespace std;const int maxn 1000;struct bign {int d[maxn], len;void clean() {while (len > 1 &&…

牛客题霸 [最长公共子序列] C++题解/答案

牛客题霸 [最长公共子序列] C题解/答案 题目描述 给定两个字符串str1和str2&#xff0c;输出连个字符串的最长公共子序列。如过最长公共子序列为空&#xff0c;则输出-1。 题解&#xff1a; dp经典问题 代码&#xff1a; class Solution { public:/*** longest common su…

2021牛客暑期多校训练营4 G-Product(组合意义+容斥原理)

G-Product Spy_Savior题解 Ultraman-Ace题解 组合意义容斥原理 转化后题目关键要求有DnkDnkDnk个小球放在nnn个盒子中&#xff0c;每个盒子至少有k个小球的方案数。 题目的等价式子为 ∑∑i1naiDnk[ai≥k]D!∏i1nai!\sum_{\sum_{i1}^na_iDnk[a_i\ge k]}\frac{D!}{\prod_{i1}^…

P6122-[NEERC2016]Mole Tunnels【模拟费用流】

正题 题目链接:https://www.luogu.com.cn/problem/P6122 题目大意 给出nnn个点的一棵满二叉树&#xff0c;每个点有容量cic_ici​&#xff0c;mmm次从pip_ipi​处加一只仓鼠然后求每只仓鼠都到一个点的最短路径长度和。 1≤n≤1051\leq n\leq 10^51≤n≤105 解题思路 模拟费…

牛客题霸 [矩阵查找] C++题解/答案

牛客题霸 [矩阵查找] C题解/答案 题目描述 请写出一个高效的在m*n矩阵中判断目标值是否存在的算法&#xff0c;矩阵具有如下特征&#xff1a; 每一行的数字都从左到右排序 每一行的第一个数字都比上一行最后一个数字大 例如&#xff1a; 对于下面的矩阵&#xff1a; [ [1, 3,…

AtCoder Beginner Contest 211 E - Red Polyomino(暴力+状态记录)

E - Red Polyomino 暴力&#xff0c;对于状态的记录考虑下面用set<vector<string>> mp #include<bits/stdc.h> using namespace std; using lllong long; template <class Tint> T rd() {T res0;T fg1;char chgetchar();while(!isdigit(ch)) {if(ch-…

CF960G-Bandit Blues【第一类斯特林数,分治,NTT】

正题 题目链接:https://www.luogu.com.cn/problem/CF960G 题目大意 求有多少个长度为nnn的排列&#xff0c;使得有AAA个前缀最大值和BBB个后缀最大值。 0≤n,A,B≤1050\leq n,A,B\leq 10^50≤n,A,B≤105 解题思路 显然的是把最大的数两边然后左边的是前缀最大值&#xff0c;…