泛型(generic)是C#语言2.0和通用语言运行时(CLR)的一个新特性。泛型为.NET框架引入了类型参数(type parameters)的概念。类型参数使得设计类和方法时,不必指定方法有一个或多个具体参数,而是在调用方法的时候再去指定。这意味着使用泛型的类型参数T,写一个方法MyList,客户代码可以这样调用:MyList< int >, MyList< string >,也就是说一个方法就可以满足不同场景的使用。避免了运行时类型转换或装箱操作的代价和风险。
为什么要有泛型,什么时候才用到泛型
以前类型的泛化(generalization)是靠类型与全局基类System.Object的相互转换来实现。比如.NET框架基础类库的ArrayList容器类,就是这种局限的一个例子。ArrayList是一个很方便的容器类,使用中无需更改就可以存储任何引用类型或值类型。
避免隐式装箱和拆箱
相对于数组来说,这种集合比数组灵活(数组长度固定,数据类型单一),但是这种便利是有代价的,这需要把任何一个加入ArrayList的引用类型或值类型都隐式地向上转换成System.Object(如上图所示)。
如果这些元素是值类型,那么当加入到列表中时,它们必须被装箱;当重新取回它们时,要拆箱。类型转换和装箱、拆箱的操作都降低了性能;在必须迭代(iterate)大容器的情况下,装箱和拆箱的影响可能十分显著。
泛型类
class MyStack<T>
{
private T[] stack;
private int size;
private int stackPoint;
public MyStack(int size)
{
this.size = size;
this.stack = new T[size];
this.stackPoint = -1;
}
//入栈
public void Push(T t)
{
if (stackPoint >= size)
{
Console.WriteLine("已满");
}
else
{
stackPoint++;
this.stack[stackPoint] = t;
}
}
//出栈
public T Pop()
{
T t = this.stack[stackPoint];
stackPoint--;
return t;
}
}
static void Main(string[] args)
{
MyStack<int> myStack = new MyStack<int>(5);
myStack.Push(1);myStack.Push(2);myStack.Push(3);myStack.Push(4);myStack.Push(5);
Console.WriteLine(myStack.Pop());
Console.WriteLine(myStack.Pop());
Console.WriteLine(myStack.Pop());
Console.WriteLine(myStack.Pop());
Console.WriteLine(myStack.Pop());
Console.ReadLine();
}
泛型方法
static void Main(string[] args)
{
Add<int>(1, 2);
Add<string>("a", "b");
Console.Read();
}
static void Add<T>(T a,T b)
{
Console.WriteLine(a+"和"+b);
}
泛型类中的数据约束
class MyGenericClass2<T1, T2, T3>
where T1:struct//类型必须是值类型
where T2:class//类型必须是引用类型
where T3:new()//类型必须有一个无参数构造方法
//其他类型:基本类型,接口类型
{
//产品列表
public List<T2> ProductList { get; set; }
//发行者
public T3 Publisher { get; set; }
public MyGenericClass2()
{
ProductList = new List<T2>();
Publisher = new T3();
}
public T2 Buy(T1 num)
{
//return ProductList[num];//通过下标访问的时候,num不能确定就是int类型
dynamic a = num;
return ProductList[a];
}