c#中的泛型、委托、泛型委托、Action和Func及使用场景系列之一:泛型
本系列将分别介绍泛型和委托的概念,比较泛型和委托在使用场景上的本质不同点,
最后介绍泛型委托结合起来如何使用及.net自身提供的两个泛型委托Action和Func。
---------------------------------------------------------分隔符--------------------------------------------------------
泛型是C#2.0中推出的功能,目的是解决类型强制转换的效率和风险问题,泛型可以作用于接口、类、方法、事件和委托,
在使用泛型前,我们先看泛型是如何引入的,考虑下面的开发场景:向一个集合中添加元素,然后遍历输出元素,代码如下:
1 public class Class1 2 { 3 public void Test() 4 { 5 ArrayList list = new ArrayList(); 6 list.Add("aaa"); 7 list.Add("bbb"); 8 9 for(int i=0;i<list.Count;i++) 10 { 11 string str = (string)list[i]; 12 } 13 } 14 15 }
因为ArrayList中的元素是object 类型的,所以用Add( )方法添加元素的时候有一个装箱(Boxing)的过程(将string转化为object),
这样在遍历使用的时候需要做拆箱(UnBoxing)的操作,即强制将object转化成string类型后再使用。
在装箱和拆箱的过程中就会损失性能和效率,而且弱类型对编程不友好,会带来意外的风险,换成泛型集合后代码如下:
1 public void Test2() 2 { 3 List<string> list2 = new List<string>(); 4 list2.Add("aaa"); 5 list2.Add("bbb"); 6 7 for (int i = 0; i < list2.Count; i++) 8 { 9 string str = list2[i]; 10 } 11 }
声明集合类的时候就指明该集合中的元素只能接收字符串List<string>( ) ,遍历的时候也无需强制转换。
场景二 : 根据传入的值比较大小并返回较大的那个值
1 public class Class1 2 { 3 private int x1, y1; 4 public Class1(int x, int y) 5 { 6 this.x1 = x; 7 this.y1 = y; 8 } 9 public int GetBigger() 10 { 11 return x1 > y1 ? x1 : y1; 12 } 13 14 }
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 6 Class1 c1 = new Class1(3, 5); 7 int i = c1.GetBigger(); 8 Console.WriteLine(i); 9 10 11 Console.ReadLine(); 12 } 13 }
以上代码只能比较int型值,如果我们要比较两个浮点数的大小,Class1是不能复用的,必须再写Class2来满足这样的需求,
可以预见,Class1和Class2除了类型不同外,代码几乎一模一样,作为一个程序员我们不能给自己挖坑,
这里该泛型上场了,泛型特性提供了一种更优雅的方式,让多个类型共享一组代码,
我们用泛型来改造Class2,而不仅仅是对Class1做复制粘贴,将Class2写成一个泛型类代码如下:
1 public class Class2<T> where T: IComparable 2 { 3 private T x1, y1; 4 public Class2(T x, T y) 5 { 6 this.x1 = x; 7 this.y1 = y; 8 } 9 public T GetBigger() 10 { 11 return x1.CompareTo(y1)>0 ? x1 : y1; 12 } 13 }
在泛型类Class2中,我们在类名Class2后加了“<T>”这样一个泛型标记,T是一个类型占位符,用尖括号括起来放在类名后面,
有了这个声明后在这个类的内部就可以使用这个类型," where T: IComparable " 为泛型约束(where是关键字),
它告诉外部的调用者,传入的类型必须实现IComparable这个接口,否则编译器就会报错。因为类型 T 实现了IComparable接口,
所以GetBigger()方法中可以调用T类型的CompareTo()方法来比较两个数的大小(c#中所有的数值类型都实现了IComparable接口)。
调用代码如下(见红色代码部分):
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 6 Class1 c1 = new Class1(3, 5); 7 int i = c1.GetBigger(); 8 Console.WriteLine(i); 9 10 11 Class2<double> c2 = new Class2<double>(3.5, 5.2); 12 double i2 = c2.GetBigger(); 13 Console.WriteLine(i2); 14 15 16 Console.ReadLine(); 17 } 18 }
在调用的时候,可以明显看到Class1和Class2构造的不同,Class2后面多了" <double> " 这样一个泛型声明,
所以Class2构造函数传入的数必须是double型的,如果我们要比较整型数的大小,就可以直接复用Class2这个泛型类了,
代码如下(红色部分) :
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 6 Class1 c1 = new Class1(3,5); 7 int i = c1.GetBigger(); 8 Console.WriteLine(i); 9 10 11 Class2<double> c2 = new Class2<double>(3.5, 5.2); 12 double i2 = c2.GetBigger(); 13 Console.WriteLine(i2); 14 15 16 Class2<int> c22 = new Class2<int>(99, 87); 17 int i22 = c22.GetBigger(); 18 Console.WriteLine(i22); 19 20 21 Console.ReadLine(); 22 } 23 }
只需在声明的时候传入int 类型就可以了,这样代码写起来就舒服多了。
--------------------------------------------------------------------分隔符---------------------------------------------------------------------------------
接下来我们看泛型方法的使用 :
明白了泛型类的使用,泛型方法的使用是类似的,定义泛型方法只需要在方法名后加上 "<T>"就可以了,如果有两个泛型类型,
就用逗号分隔两个泛型标识符,如 "<T1, T2>",多个泛型类型以此类推,我们将上面比较大小的功能用泛型方法来实现,代码如下:
1 public class Class3 2 { 3 public T GetBigger<T>(T x1, T y1) where T:IComparable 4 { 5 return x1.CompareTo(y1) > 0 ? x1 : y1; 6 } 7 }
方法名GetBigger和方法参数之间加上泛型标记 "<T>" ,因为是比较两个数的大小,所以要对类型T用where做一下约束,
类型T必须实现IComparable接口(这个接口只有一个CompareTo( )方法), 这样类型变量 x1 才能调用CompareTo( ) 方法来比较大小。
调用的方式如下(见红色代码部分):
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 6 Class1 c1 = new Class1(3,5); 7 int i = c1.GetBigger(); 8 Console.WriteLine(i); 9 10 11 Class2<double> c2 = new Class2<double>(3.5, 5.2); 12 double i2 = c2.GetBigger(); 13 Console.WriteLine(i2); 14 15 16 Class2<int> c22 = new Class2<int>(99, 87); 17 int i22 = c22.GetBigger(); 18 Console.WriteLine(i22); 19 20 21 Class3 c3 = new Class3(); 22 int i3 = c3.GetBigger<int>(82, 37); 23 Console.WriteLine(i3); 24 25 26 Console.ReadLine(); 27 } 28 }
如果要比较浮点数只需在调用GetBigger方法的时候将尖括号中的int替换成double就可以了(返回值i3的类型也要换成double),实现了代码的复用。
接下来一篇将介绍c#中的委托。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人