C# 泛型
泛型:
允许多种类型共享一组代码。在声明泛型时,给出类型参数,然后用不同类型创建实例。也就是在事先使用类型占位符,在实例化时才指出真实类型。
1、为什么要有泛型
2、哪些情况下会使用到泛型
我们在编程程序时,经常会遇到功能非常相似的模块,只是它们处理的数据不一样。但我们没有办法,只能分别写多个方法来处理不同的数据类型。这个时候,那么问题来了,有没有一种办法,用同一个方法来处理传入不同种类型参数的办法呢?泛型的出现就是专门来解决这个问题的。
不同类型对象的相同逻辑处理就可以选择泛型。
/// <summary> /// 显示数据 /// </summary> /// <param name="value"></param> public static void Show(int value) { Console.WriteLine(value); } /// <summary> /// 显示数据 /// </summary> /// <param name="value"></param> public static void Show(string value) { Console.WriteLine(value); } /// <summary> /// 显示数据 /// </summary> /// <param name="value"></param> public static void Show(DateTime value) { Console.WriteLine(value); }
不使用泛型我们怎么办?
/// <summary> /// 显示数据 /// </summary> /// <param name="value"></param> public static void Show(object value) { Console.WriteLine(value); }
为什么可以?
object是所有类型的基类,但是object类型的方法又会带来另外一个问题:装箱和拆箱,会损耗程序的性能
泛型写法:
/// <summary> /// /// </summary> /// <typeparam name="T"></typeparam> /// <param name="value"></param> public static void Show<T>(T value) { Console.WriteLine(value); }
优缺点:
1、性能
对值类型使用非泛型集合类,在把值类型转换为引用类型,和把引用类型转换为值类型时,需要进行装箱和拆箱操作。装箱和拆箱的操作很容易实现,但是性能损失较大。假如使用泛型,就可以避免装箱和拆箱操作。
2、类型安全
泛型类使用泛型类型,并可以根据需要用特定的类型替换泛型类型。这就保证了类型安全性:如果某个类型不支持泛型类,编译器就会报错。
3、提升代码重用
4、易与代码扩展
在定义泛型类时,可以对客户端代码能够在实例化类时用于类型参数的类型种类施加限制。如果客户端代码尝试使用某个约束所不允许的类型来实例化类,则会产生编译时错误。这些限制称为约束。
泛型五种常用约束类型:值类型、引用类型、公共构造函数、基类和接口
值类型约束:
要求类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型。 例如int,short以及自定义的struct等 //这个泛型类只接受值类型的泛型参数 public class Class where T : struct { } //可以与接口约束同时使用,并且要在最前面(不能与基类约束,构造函数约束一起使用)
public class Class where T : struct, IComparable { }
引用类型约束:
要求类型参数必须是引用类型,包括任何类、接口、委托或数组类型
例如string,object,以及自定义的class
这个泛型类只接受引用类型的泛型参数
public class Class where T : class { }
构造函数约束:
类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最 后指定。
public class Class where T : new() { }
可以将构造函数约束和其他约束组合起来,前提是构造函数约束出现在约束列表的最后
public class Class where T : IComparable, new() { }
基类约束:
要求类型参数必须是指定的基类或派生自指定的基类。
public class Class where T : BaseClass { }
接口约束:
要求类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可 以是泛型的。
public class Class where T : System.IComparable { }
约束放在类的实际派生之后
public class BASE { } public class Class : BASE where T : IComparable { }
可以继承一个基类和多个接口,且基类在接口前面
public class Class where T : BASE, IComparable, ICloneable { }
多参数多约束条件示例:
public class BaseClass { } public class A<T1, T2, T3, T4, T5> where T1 : struct where T2 : class where T3 : new() where T4 : BaseClass, new() where T5 : IComparable { }
类型参数的约束和次序:
1、使用where子句对类型参数进行约束,where子句之间没有标点符号
2、如果某个类型参数有多个约束,在每一个where子句中用逗号间隔。
3、where子句的约束必须有一定的顺序,最多只能有一个主约束。
4、可以有任意多的接口名约束。
5、如果存在构造函数约束,则必须放在最后。
无限接近死亡,才能领悟生命的真谛
标签:
C#
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 全程使用 AI 从 0 到 1 写了个小工具
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)