当您反汇编生成的代码时,您可以看到在.NET3.5中
ldtoken
按照如下方式发出与开放通用方法相关的指令:
.method public static void GeneratedMethod<T>() cil managed
{
// Code size 11 (0xb)
.maxstack 1
IL_0000: ldtoken method instance void [ConsoleApplication16]ConsoleApplication16.Program/Foo::FooMethod<!!0>()
IL_0005: call void [ConsoleApplication16]ConsoleApplication16.Program::PrintMethodInfo(valuetype [mscorlib]System.RuntimeMethodHandle)
IL_000a: ret
} // end of method TestType::GeneratedMethod
语法
!!0
是对周围方法的类型参数的引用(
GeneratedMethod
),所以
Foo
方法的实例加载
T
属于
GeneratedMethod<T>
。(事实上,这与为
IL.Emit (OpCodes.Ldtoken, methodInfo.MakeGenericMethod (<typeParameterOfGeneratedMethod>))
.)这个
!!0
即使在
生成的方法
根本不是通用的——生成的程序不再可验证(并且在执行时会导致BadImageFormatException)。
这显然是一个错误,在.NET4中,这似乎已经修复,因为(已分解的)发出的代码现在看起来是这样的:
.method public static void GeneratedMethod<T>() cil managed
{
// Code size 11 (0xb)
.maxstack 1
IL_0000: ldtoken method instance void [ConsoleApplication16]ConsoleApplication16.Program/Foo::FooMethod<[1]>()
IL_0005: call void [ConsoleApplication16]ConsoleApplication16.Program::PrintMethodInfo(valuetype [mscorlib]System.RuntimeMethodHandle)
IL_000a: ret
} // end of method TestType::GeneratedMethod
正如您所看到的,签名现在指的是未实例化的
FooMethod
(在IL组件中,表示为
FooMethod[1]
)。
所以,是的,这看起来像是.NET 3.5中的一个错误,它是用.NET 4修复的。然而,这似乎并没有改变
ld令牌
;只是Reflection.Emit没有正确地发出打开泛型方法的引用。我怀疑它也与
the fact that IL assembler didn't even have a syntax to denote open generic methods in the past
。