先简单的说一下泛型的作用,假如我们设计一个支持整形的排序函数,然后又需要一个支持浮点类型的排序函数,这样的写两份相似的代码,违反了OOP的原则。利用转型为object,又有封箱拆箱和安全性的问题。所以我们利用泛型,让程序到运行时才去确定到底是要用什么类型。
C#的泛型类似于C++中的模版但是不论在设计上还是功能上都有很多不同。具体可以参考MSDN中的介绍。
泛型的使用
先看一段代码
1: class Program
2: {
3: static void TestMethod(U u1)
4: {
5: Console.WriteLine(u1.ToString());
6: }
7: static void Main(string[] args)
8: {
9: int number = 10;
10: string str = "String";
11: TestMethod<int>(number);
12: TestMethod<string>(str);
13: Console.ReadKey();
14: }
15: }
可以看出TestMethod函数设计时并没有设定特定的参数类型,直到运行时才确定具体的类型是int还是string 或者其他类型。
明显可以看出使用泛型大大提高了代码的复用率。
C#泛型的机制
C#泛型能力有CLR在运行时支持
C#泛型代码在编译为IL代码和元数据时,采用特殊的占位符来表示范型类型,并用专有的IL指令支持泛型操作。
而真正的泛型实例化工作以“on-demand”的方式,发生在JIT编译时。
第一轮编译时,编译器只产生“泛型版”的IL代码与元数据——并不进行泛型的实例化,T在中间只充当占位符。
JIT编译时,当JIT编译器第一次遇到泛型版时,将用特定的类型(如int)替换“范型版”IL代码与元数据中的T——进行泛型类型的实例化。
CLR为所有类型参数为“引用类型”的泛型类型产生同一份代码;但是如果类型参数为“值类型”,对每一个不同的“值类型”,CLR将为其产生一份独立的代码。
因为实例化一个引用类型的泛型,它在内存中分配的大小是一样的,但是当实例化一个值类型的时候,在内存中分配的大小是不一样的。
泛型类与泛型委托
泛型不仅支持方法,还支持类,委托,接口等。
具体的使用于泛型方法类似
1: //泛型类
2: public class Test
3: {
4: private T member;
5: public Test(T member)
6: {
7: this.member = member;
8: }
9: public void Output()
10: {
11: Console.WriteLine(member.ToString());
12: }
13: }
14: class Program
15: {
16: static void Main(string[] args)
17: {
18: Test<int> t1 = new Test<int>(10);
19: Test<string> t2 = new Test<string>("string");
20: t1.Output();
21: t2.Output();
22: Console.ReadKey();
23: }
24: }
25:
26: //泛型委托
27: class Program
28: {
29: private delegate void TestDelegate(T output);
30:
31: static void Test(T output)
32: {
33: Console.WriteLine(output.ToString());
34: }
35:
36: static void Main(string[] args)
37: {
38: TestDelegate<int> d1;
39: d1 = Test<int>;
40: TestDelegate<string> d2;
41: d2 = Test<string>;
42:
43: d1(10);
44: d2("string");
45:
46: Console.ReadKey();
47: }
48: }
泛型约束
上面的泛型都是可以支持任何类型,但是我们有时候希望,他只要支持某些类和他的子类。或者说只支持值类型,甚至是两个泛型参数之间有继承关系。
这一些都可以利用where关键字来限定,这些限定我们成为泛型约束。
T:struct 类型参数必须是值类型。
T:class 类型参数必须是引用类型,包括任何类、接口、委托或数组类型。
T:new() 类型参数必须具有无参数的公共构造函数。(当与其他约束一起使用时,new() 约束必须最后指定。)
T:<基类名> 类型参数必须是指定的基类或派生自指定的基类。(不可以于T:class一起使用)
T:<接口名称> 类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。
T:U 为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。这称为裸类型约束。
1: class TestBase
2: {
3: public int foo;
4:
5: public TestBase()
6: {
7: foo = 10;
8: }
9:
10: public TestBase(int f)
11: {
12: foo = f;
13: }
14: }
15:
16: class Program
17: {
18: static void TestMethod(T t1) where T:TestBase where U:T,new()
19: {
20: U u1 = new U();
21: Console.WriteLine("{0} + {1}",t1.foo,u1.foo);
22: }
23: static void Main(string[] args)
24: {
25: TestBase t = new TestBase(11);
26: TestMethod(t);
27: Console.ReadKey();
28: }
29: }
这些限定让泛型有了很大的规范性,能避免很多问题。
泛型类继承
关于泛型类的继承问题。有一个简单的原则基类如果是泛型类,它的类型要么以实例化,要么来源于子类(同样是泛型类型)声明的类型参数
1: class C { }
2: class D : C<string, int> { }
3: class E : C { }
4: class F : C<string, int> { }
5: //基类如果是泛型类,他的类型参数要么已实例化,
6: //要么来源子类(同样是泛型类型)声明的类型参数。
7: //class G : C { } 非法
关于泛型的多态
由于泛型是运行时才能确定具体的类型,在多态方面有一点点特别,容易产生二义性,如果同时存在确定类型的方法会默认先调用确定类型的方法,而后才寻找可能的泛型方法。
1: public class Test
2: {
3: public void TestMethod(T t1, U u1)
4: {
5: Console.WriteLine("1");
6: }
7: public void TestMethod(U u1, T t1)
8: {
9: Console.WriteLine("2");
10: }
11: public void TestMethod(int t, int u)
12: {
13: Console.WriteLine("3");
14: }
15: }
16: class Program
17: {
18: static void Main(string[] args)
19: {
20: Test<int,int> t1 = new Test<int,int>();
21: t1.TestMethod(123, 123);//call public void TestMethod(int t, int u)
22:
23: Test<string, int> t2 = new Test<string, int>();
24: t2.TestMethod("123", 123);//call public void TestMethod(T t1, U u1)
25:
26: //Testt3 = new Test ();
27: //t3.TestMethod("123", "123");//产生二义性
28:
29: Console.ReadKey();
30: }
31: }
http://msdn.microsoft.com/zh-cn/library/sx2bwtw7%28v=VS.80%29.aspx
http://msdn.microsoft.com/zh-cn/library/twcad0zb%28v=VS.80%29.aspx
http://msdn.microsoft.com/zh-cn/library/sz6zd40f%28v=VS.80%29.aspx
http://msdn.microsoft.com/zh-cn/library/0x6a29h6%28v=VS.80%29.aspx
http://msdn.microsoft.com/zh-cn/library/b5bx6xee%28v=VS.80%29.aspx
http://msdn.microsoft.com/zh-cn/library/d5x73970%28v=VS.80%29.aspx
http://msdn.microsoft.com/zh-cn/library/c6cyy67b%28v=VS.80%29.aspx
http://msdn.microsoft.com/zh-cn/library/xwth0h0d%28v=VS.80%29.aspx
http://www.cnblogs.com/lianyonglove/archive/2007/04/20/720682.html
http://dev.csdn.net/htmls/80/80696.html
http://www.cnblogs.com/kid-li/archive/2006/11/29/577045.html
http://www.blogjava.net/Jack2007/archive/2008/05/05/198566.html