[Programming IL]泛型, Generic Types
引言:
自从泛型那天诞生起,广大的面向对象程序员对于他的热爱普遍要高于其他数据结构. :). 然而各大面向对象对于他的支持却不太一样。在CPP中用的是静态编译,即在编译器决定泛型的类型,而.Net则是在运行时确定,他们有什么不一样呢?
和周围的同事谈起泛型,发现大伙对于这东西都是似懂非懂,觉得自己有必要作一次应用总结了. :( , 由于范型内容较多,请看这里:
我们从C#总定义一段基本的范型代码开始
1: public class GenericType<T> : IComparable<T>, IComparable<GenericType<T>>
2: where T: IComparable
3: {
4: public T Value;
5:
6: public int CompareTo(T t)
7: {
8: return this.Value.CompareTo(t);
9: }
10:
11: public int CompareTo(GenericType<T> t)
12: {
13: return this.Value.CompareTo(t.Value);
14: }
15: }
反编译后的IL代码
1: .class public auto ansi beforefieldinit GenericType`1<([mscorlib]System.IComparable) T>
2: extends [mscorlib]System.Object
3: implements class [mscorlib]System.IComparable`1<!T>,
4: class [mscorlib]System.IComparable`1<class GenericType`1<!T>>
5: {
6: .field public !T Value
7: .method public hidebysig newslot virtual final
8: instance int32 CompareTo(!T t) cil managed
9: {
10: // Code size 24 (0x18)
11: .maxstack 8
12: IL_0000: ldarg.0
13: IL_0001: ldflda !0 class GenericType`1<!T>::Value
14: IL_0006: ldarg.1
15: IL_0007: box !T
16: IL_000c: constrained. !T
17: IL_0012: callvirt instance int32 [mscorlib]System.IComparable::CompareTo(object)
18: IL_0017: ret
19: } // end of method GenericType`1::CompareTo
20:
21: .method public hidebysig newslot virtual final
22: instance int32 CompareTo(class GenericType`1<!T> t) cil managed
23: {
24: // Code size 29 (0x1d)
25: .maxstack 8
26: IL_0000: ldarg.0
27: IL_0001: ldflda !0 class GenericType`1<!T>::Value
28: IL_0006: ldarg.1
29: IL_0007: ldfld !0 class GenericType`1<!T>::Value
30: IL_000c: box !T
31: IL_0011: constrained. !T
32: IL_0017: callvirt instance int32 [mscorlib]System.IComparable::CompareTo(object)
33: IL_001c: ret
34: } // end of method GenericType`1::CompareTo
35:
36: .method public hidebysig specialname rtspecialname
37: instance void .ctor() cil managed
38: {
39: // Code size 7 (0x7)
40: .maxstack 8
41: IL_0000: ldarg.0
42: IL_0001: call instance void [mscorlib]System.Object::.ctor()
43: IL_0006: ret
44: } // end of method GenericType`1::.ctor
45:
46: } // end of class GenericType`1
我们将之拆解为几个简单的部分来讨论
1. 定义一个泛型类
这个部分又大可以分拆为
- 声明一个类
1: .class public GenericType <([mscorlib]System.IComparable) T>
2: extends [mscorlib]System.Object
3: implements class [mscorlib]System.IComparable<!T>
4: class [mscorlib]System.IComparable<class GenericType<T>>
5: {
6: }
与声明一个非泛型类而言不同的就是
- 声明变量
1: .class public value Pair<T>
2: {
3: .field public !T x
4: .field public !T y // fields x and y have the same type T
5: }
- 声明方法
1: .class public List`1<T>
2: {
3: .method public void Append(!T val) { ... }
4: .method public !T GetLast() { ... }
5: //...
6: }
- 隐藏与覆盖
1: <([mscorlib]System.IComparable) T>
这个部分,泛型的实现与非泛型一致,我们可以查看一个实例
我们为之前定义的GenericType定义两个方法
1: public void BaseRun()
2: {
3: Console.WriteLine("This is the base Run");
4: }
5:
6: public virtual void ParentMethod()
7: {
8: Console.WriteLine("The is the parentVirtual Method");
9: }
再为他定义一个基类DerivedClass
1: public class DerivedClass<T> : GenericType<T>
2: where T : IComparable
3: {
4: public new void BaseRun()
5: {
6: Console.WriteLine("This is the derived class running");
7: }
8:
9: public override void ParentMethod()
10: {
11: Console.WriteLine("This is the derived class");
12: }
13: }
对比下生成的IL代码
1: .method public hidebysig instance void BaseRun() cil managed
2: {
3: // Code size 11 (0xb)
4: .maxstack 8
5: IL_0000: ldstr "This is the derived class running"
6: IL_0005: call void [mscorlib]System.Console::WriteLine(string)
7: IL_000a: ret
8: } // end of method DerivedClass`1::BaseRun
9:
10: .method public hidebysig virtual instance void
11: ParentMethod() cil managed
12: {
13: // Code size 11 (0xb)
14: .maxstack 8
15: IL_0000: ldstr "This is the derived class"
16: IL_0005: call void [mscorlib]System.Console::WriteLine(string)
17: IL_000a: ret
18: } // end of method DerivedClass`1::ParentMethod
2. 定义约束
参考之前提到的几种约束,我们分别用IL来做一下解释
- 值类型约束
1: .class public ClassType`1<valuetype .ctor ([mscorlib]System.ValueType) T>
2: extends [mscorlib]System.Object
3: {}
- 引用类型约束
1: .class public ClassType`1<class T> extends [mscorlib]System.Object
- 接口类型约束
- 参考本文前面的代码
- 基类约束
1: .class public BaseClass`1<(class GenericType`1<!T>, [mscorlib]System.IComparable) T>
2: extends [mscorlib]System.Object
- 无参构造函数约束
1: .class public auto ansi beforefieldinit CtorType`1<.ctor T>
2: extends [mscorlib]System.Object
- 多个泛型类型关系约束
1: .class public ParentChild`2<T, (!T)U> // U must bedescendant of T
2: {
3: //TODO:: Implement this ...
4: }
- (!T)U代表了U必须是可以通过类型转换变成T,即U为T的子类
- 来个复杂点的
1: .class public auto ansi beforefieldinit ComplexType`1<class .ctor ([mscorlib]System.IComparable) T>
2: extends [mscorlib]System.Object
可以看到,几种类型定义的不同只存在于 <类型定义>
走到这里,我还是不明白,虽然在IL层次上的东西做的相当的简洁,那泛型那些优势又是如何实现的呢,去看了下元数据定义也没啥惊喜
元数据定义:
Generic Param(泛型参数), 即<类型定义>:
GenericParam Metadata Table:
名称 | 作用 |
Number(2-byte unsigned integer). |
泛型类型中泛型参数的位置 |
Flags(2-byte bit field). |
代表泛型约束 |
Owner(coded token of type TypeOrMethodDef). |
泛型参数所对应的泛型类型 |
Name(offset in the #Strings stream). |
泛型参数名称 |
Generic Method(泛型方法):
1: <gen_method_def> ::=
2: .method <flags> <call_conv> <ret_type> <name>< <gen_params> > (<arg_list>) <impl>
3: { <method_body> }
4: For example:
5: .method public static !!T GetMedian<T>(!!T[] tarray)
6: {
7: ldarg.0
8: dup
9: ldlen
10: ldc.i4.1
11: shr
12: ldelem !!T
13: ret
14: }
关于CLR对于运行时创建好像很难找到相关资料,有待进一步深入了 :), 本文断断续续也写了很久了,先画上一个句号吧
参考
- Expert IL Assembler 2.0
- Professional.Net 2.0 Generic
- ECMA Partion II