简单分析.net泛型中的类型参数2011-03-31 csdn博客 傅晗一位朋友询问tppeof、GetType()、is、as的问题,在实验的时候顺手就用泛型写的例子。在看Jit后的反汇编时发现了一个问题,clr对泛型参数有些特殊处理。上网查了一下没有找到介绍泛型参数存储的文章因此动手做了一番实验,有了些浅显的理解在此记录下来望看到此文的高手能给予全面的解释。以前用泛型的时候没想过clr是如何处理泛型参数的,今天查阅了下<<Expert .NET 2.0 IL Assembler>>里面讲解了一个叫做GenericParam Metadata Table的数据结构,不过没能解决我的疑惑。先来看段代码:class C<T, U, V> where T: class
{
public void Test_Class(V v)
{
Debugger.Break();
T t = v as T;
}
public void Test_Method<X, Y>(X x, Y y)
{
Debugger.Break();
Type type1 = typeof(X);
Type type2 = typeof(Y);
}
}
class Test
{
static void Main()
{
C<Type, string, object> c = new C<Type, string, object>();
string s = "ok";
object o = s;
c.Test_Class(o);
c.Test_Method(s, o);
}
}
我们先执行Test_Class方法,当进入Test_Class方法后部分主要反汇编及注释如下:T t = v as T;
0000003e mov eax,dword ptr [ebp-3Ch] //1.得到this指针 01E52B30
00000041 mov eax,dword ptr [eax] //2.得到C<T, U, V>的方法表地址 002A3918
00000043 mov eax,dword ptr [eax+20h] //3.得到存储泛型参数的地址 002A3954
00000046 mov eax,dword ptr [eax] //4.保存参数类型的地址 002a3958
00000048 mov eax,dword ptr [eax] //5.得到T参数的真实类型,既方法表地址 6C18172C
0000004a mov dword ptr [ebp-48h],eax
0000004d test dword ptr [ebp-48h],1
00000054 jne 0000005B
00000056 mov ecx,dword ptr [ebp-48h] //将T的方法表地址传给ECX准备call as方法
00000059 jmp 00000061
0000005b mov eax,dword ptr [ebp-48h]
0000005e mov ecx,dword ptr [eax-1]
00000061 mov edx,dword ptr [ebp-40h] //得到参数o
00000064 call 6C0598F3 //调用as方法
汇编的前两句很好理解就是得到this指针后根据托管对象头4字节找方法表地址,第三句是在方法表偏移20h出得到类型泛型参数信息,不过这里要说明一点在msdn上有篇文章《深入探索.NET框架内部了解CLR如何创建运行时对象》里面的有张ethodTable Layout的图解,不过那个图好像是.net1.1的和.net2.0的方法表layout已经不一样了。我通过测试确定了其中一些字节的涵义(希望有高手给我一份完整的解释)如下所示:00 = Flags
04 = Instance Size
08 = ??
0C = ??
10 = ??
14 = Module addr
18 = Mehtod Table End addr
1C = EEClass addr (泛型类时,这里的含义不明)
20 = GenericParam Info addr
24 = Gobal Interface Map Table addr(?)
28 = ToString()
2C = Equals()
30 = GetHashCode()
34 = Finalize()
…… 类中的虚方法入口地址
…… 非泛型类的构造函数入口地址
…… interface table addr(如果继承了接口)
…… 一个四字节,记录泛型参数个数不知道是否还有其他涵义(如果是泛型类)
…… interface table
…… GenericParam Info(如果是泛型类)