一、定义
泛型:通过参数化类型来实现在同一份代码上操作多种数据类型。利用“参数化类型”将类型抽象化,从而实现灵活的复用。
//Compare<T>为泛型类,T为类型参数
public class Compare<T> where T : IComparable
{
public static T CompareGeneric( T t1, T t2 )
{
if( t1.CompareTo( t2 ) > 0 )
{
return t1;
}
else
{
return t2;
}
}
}
class Program
{
static void Main( string[ ] args )
{
//调用泛型方法
Console.WriteLine( Compare<int>.CompareGeneric(3,4) );
Console.WriteLine( Compare<string>.CompareGeneric( "abc", "a" ) );
Console.Read( );
}
}
运行结果:
二、解析泛型
1. 类型参数
根据泛型类型参数是否提供实际类型,可把泛型分成两类:未绑定的泛型和已构造的泛型。
未绑定泛型:没有为类型参数提供实际类型
已构造泛型:已指定了实际类型作为参数
2. 泛型中静态字段和静态函数问题
每个密封的泛型类型中都有仅属于它自己的静态数据,对于构造函数,也是如此,每个密封的泛型类型都有一个静态构造函数。
3. 泛型类型的约束
约束 | 说明 | 示例 |
引用类型约束,T:class | 确保传递的类型实参必须是引用类型,它可以为任何的类、接口、委托或数组 | using System.IO; //传入的类型实参必须是System.IO.Stream,或者是从Stream派生的一个类型 public class samplereference<T> where T:Stream { public void Test(T stream) { stream.Close(); } } |
值约束类型,T:struct | 确保传递的类型实参是值类型(包括枚举) | public class samplevaluetype<T> where T:struct { public static T Test() { //所有值类型都有一个公共的无参构造函数 return new T(); } } |
转换类型约束 T:基类名 T:接口名 T:U | T:基类名,确保指定的类型实参必须是基类或派生自基类的子类 T:接口名,确保指定的类型实参必须是接口或者实现了该接口的类 T:U,确保T提供的类型实参必须是U提供的类型实参或派生于U提供的类型实参,即前面一个类型实参必须是后面的类型实参或后面类型实参子类 | class Sample<T> where T:Stream // Sample<Stream>是有效的,Sample<string>是无效的 class Sample<T> where T:IDisposable // Sample<Stream>是有效的,Sample<StringBuilder>是无效的 class Sample<T,U> where T:U // Sample<Stream,IDisposable>是有效的,Sample<string,IDisposable>是无效的 |
组合类型 | 组合约束是将多个不同种类的约束合并在一起的情况,注意:没有任何一种类型既是引用类型,又是值类型。如果存在多个转换类型约束,且其中一个是类,则类必须放在接口的前面。不同的类型参数可以有不同的约束,但每种类型参数必须分别使用一个单独的where关键字。 | 有效: class Sample<T> where T:class,Idisposable,new() class Sample<T,U> where T:class where U:struct 无效: class Sample<T> where T:class,struct //没有任何类型既是引用类型又是值类型 |