文章目录
-
-
- 一、什么是泛型?
- 二、使用泛型的好处
-
-
- 1、未使用泛型的代码
- 2、使用泛型的代码
-
- 三、泛型的使用范围
-
-
- 1、泛型方法
- 2、泛型类
- 3、泛型接口
- 4、泛型委托
- 5、泛型约束
- 6、default关键字
-
-
这篇文章主要来讲讲c#中的泛型,因为泛型在c#中有很重要的位置,对于写出高可读性,高性能的代码有着关键的作用。
一、什么是泛型?
泛型是 2.0 版 C# 语言和公共语言运行库 (CLR) 中的一个非常重要的新功能。
我们在编程程序时,经常会遇到功能非常相似的模块,只是它们处理的数据不一样。但我们没有办法,只能分别写多个方法来处理不同的数据类型。这个时候,那么问题来了,有没有一种办法,用同一个方法来处理传入不同种类型参数的办法呢?泛型的出现就是专门来解决这个问题的,可以看出,微软还是很贴心的。
二、使用泛型的好处
1、未使用泛型的代码
非泛型结构的方法,在面对参数类型不同时,需要提供不同的方法,使得代码冗余率高,影响开发效率
public class CommonMethod{
public static void ShowInt(int iParameter){
Console.WriteLine("This is {0},parameter={1},type={2}",typeof(CommonMethod).Name, iParameter.GetType().Name, iParameter);}public static void ShowString(string sParameter){
Console.WriteLine("This is {0},parameter={1},type={2}",typeof(CommonMethod).Name, sParameter.GetType().Name, sParameter);}public static void ShowDateTime(DateTime dtParameter){
Console.WriteLine("This is {0},parameter={1},type={2}",typeof(CommonMethod).Name, dtParameter.GetType().Name, dtParameter);}}
static void Main(string[] args){
CommonMethod.ShowInt(18);CommonMethod.ShowString("hello world!");CommonMethod.ShowDateTime(DateTime.Now);}
2、使用泛型的代码
泛型方法解决了用一个方法,满足不同参数类型,做同样的事情。不写死参数类型,调用的时候才指定参数的类型,由此达到延迟声明的目的。
public class GenericMethod{
/// <summary>/// 泛型方法/// </summary>/// <typeparam name="T">T 不要用关键字 也不要跟别的类型冲突 </typeparam>/// <param name="tParameter"></param>public static void Show<T>(T tParam){
Console.WriteLine("This is {0},parameter={1},type={2}",typeof(GenericMethod).Name, tParam.GetType().Name, tParam.ToString());}}
static void Main(string[] args){
GenericMethod.Show<int>(18);GenericMethod.Show<string>("hello world!");GenericMethod.Show<DateTime>(DateTime.Now);}
三、泛型的使用范围
1、泛型方法
public class GenericMethod{
public static void Show<T>(T tParameter){
Console.WriteLine("This is {0},parameter={1},type={2}",typeof(GenericMethod).Name, tParameter.GetType().Name, tParameter.ToString());}}static void Main(string[] args){
GenericMethod.Show<int>(18);GenericMethod.Show<string>("hello world!");GenericMethod.Show<DateTime>(DateTime.Now);}
泛型方法在被调用之后才确定参数的类型,我们在调用同一个方法,最后我们获取到的参数类型都是原始类型,在我们调用泛型方法,编译器进行编译时,才会确定传入参数的类型,从而生成副本方法。这个方法与原始方法一样,所以不会有装箱和拆箱的操作。
2、泛型类
class CommonNode {
}class GenericClass<T> {
}class GenericComm<T> : CommonNode {
}class GenericNode<T> : GenericClass<int> {
}class GenericOpen<T> : GenericNode<T> {
}
3、泛型接口
定义一个泛型接口:
interface IGenericInterface<T>
{
}
一个接口可定义多个类型参数:
interface IGenericInterface<TKey,TValue>
{
}
具体类可实现封闭式构造接口:
interface IBaseInterface<T> {
}class GenericClass : IBaseInterface<string> {
}
4、泛型委托
委托的方法可以定义不同类型的参数。 引用泛型委托的代码可以指定类型参数以创建封闭式构造类型,就像实例化泛型类或调用泛型方法一样。如示例所示:
class Program
{
static void Main(string[] args){
SayHi<int> hi1 = new SayHi<int>(Show);hi1.Invoke(123);SayHi<string> hi2 = new SayHi<string>(Show);hi2.Invoke("hello");}public delegate void SayHi<T>(T t);//泛型委托public static void Show(int i) {
Console.WriteLine("{0} type is {1}", i,i.GetType()); }public static void Show(string str) {
Console.WriteLine("{0} type is {1}", str, str.GetType()); }
}
5、泛型约束
约束类型 | 详解 |
---|---|
T:结构 | 类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型。有关更多信息,请参见使用可空类型(C# 编程指南)。 |
T:类 | 类型参数必须是引用类型,包括任何类、接口、委托或数组类型。 |
T:new() | 类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。 |
T:<基类名> | 类型参数必须是指定的基类或派生自指定的基类。 |
T:<接口名称> | 类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。 |
T:U | 为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。这称为裸类型约束。 |
- where T:结构
类型参数必须为值类型,可以指定除 Nullable 以外的任何值类型。
class MyClass<U>where U : struct///约束U参数必须为“值 类型”
{
}public void MyMetod<T>(T t)where T : struct
{
}
- where T:类
指出某个类型必须将指定的类作为基类(或者就是该类本身),才能用作该泛型类型的类型参数。这样的约束一经使用,就必须出现在该类型参数的所有其他约束之前。
class MyClassy<T, U>where T : classwhere U : class
{
}
- where T:new()
以使用 new 运算符创建类型参数的实例;但类型参数为此必须受构造函数约束 new() 的约束。new() 约束可以让编译器知道:提供的任何类型参数都必须具有可访问的无参数(或默认)构造函数。new() 约束出现在 where 子句的最后。
public class MyGenericClass <T> where T: IComparable, new()
{
// The following line is not possible without new() constraint:T item = new T();
}
- where T:<基类名>
指出某个类型必须将指定的类作为基类(或者就是该类本身),才能用作该泛型类型的类型参数。这样的约束一经使用,就必须出现在该类型参数的所有其他约束之前。
class MyClassy<T, U>where T : classwhere U : struct
{
}
- where T:<接口名称>
例如,可以声明一个泛型类 MyGenericClass,这样,类型参数 T 就可以实现 IComparable 接口:
public class MyGenericClass<T> where T:IComparable
{
}
- where T:U
用作约束的泛型类型参数称为裸类型约束。当具有自己的类型参数的成员函数需要将该参数约束为包含类型的类型参数时,裸类型约束很有用。
class List<T>
{
void Add<U>(List<U> items) where U : T {
/*...*/}
}
泛型类的裸类型约束的作用非常有限,因为编译器除了假设某个裸类型约束派生自 System.Object 以外,不会做其他任何假设。在希望强制两个类型参数之间的继承关系的情况下,可对泛型类使用裸类型约束。
6、default关键字
之所以会用到default关键字,是因为需要在不知道类型参数为值类型还是引用类型的情况下,为对象实例赋初值。考虑以下代码:
class TestDefault<T>
{
public T foo(){
T t = null; //???return t;}
}
如果我们用int型来绑定泛型参数,那么T就是int型,那么注释的那一行就变成了 int t = null;显然这是无意义的。为了解决这一问题,引入了default关键字:
class TestDefault<T>
{
public T foo(){
return default(T);}
}