Osk*_*ren 4 .net reflection reflection.emit .net-4.0
给定一个标识非泛型类的开放泛型方法的MethodInfo实例,请考虑以下伪代码:
class Foo { void FooMethod<T>() {} }
public static void PrintMethodInfo(RuntimeMethodHandle methodHandle)
{
var mi = (MethodInfo) MethodBase.GetMethodFromHandle(methodHandle);
Console.WriteLine("Method: "+mi.ToString());
}
var methodInfo = typeof(Foo).GetMethod("FooMethod");
Run Code Online (Sandbox Code Playgroud)
生成一个方法"void GeneratedMethod <T>()",在主体中包含此代码:
IL.Emit(OpCodes.Ldtoken, methodInfo);
IL.Emit(OpCodes.Call, methodInfoPrintMethodInfo);
Run Code Online (Sandbox Code Playgroud)
调用GeneratedMethod <int>(),.Net 3.5上的输出将是:
Method: System.Object Method[Int32]()
Run Code Online (Sandbox Code Playgroud)
在.Net 4.0上,它将是:
Method: System.Object Method[T]()
Run Code Online (Sandbox Code Playgroud)
因此,在.Net 2.0/3.5中,ldtoken生成的IL似乎将包含一个元数据标记,该标识符标识通用FooMethod <>实例化,该类型参数在调用GeneratedMethod <T>时给出.
但是,在.Net 4.0中,ldtoken将包含标识开放泛型类型的元数据.
我很难找到支持.Net 3.5案例中发生的事情的文档(事实上,如果生成的方法本身不是通用的,它应该完全失败) - .Net 4的行为似乎更合乎逻辑.我也找不到任何关于这种变化的文件.这是现在修复的早期版本中的错误吗?
当您反汇编生成的代码时,您可以看到在.NET 3.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
Run Code Online (Sandbox Code Playgroud)
语法!!0是对周围方法(GeneratedMethod)的类型参数的引用,因此该Foo方法是使用T所属的实例化加载的GeneratedMethod<T>.(实际上,这与发出的IL相同IL.Emit (OpCodes.Ldtoken, methodInfo.MakeGenericMethod (<typeParameterOfGeneratedMethod>)).)!!0即使GeneratedMethod不是通用的,也会发出此引用- 结果程序不再可验证(并且在执行时会导致BadImageFormatException).
这显然是一个错误,在.NET 4中,这似乎是固定的,因为(反汇编)发出的代码现在看起来像这样:
.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
Run Code Online (Sandbox Code Playgroud)
如您所见,签名现在指的是未实例化的FooMethod(在IL程序集中,这表示为FooMethod[1]).
所以是的,这看起来像.NET 3.5中的一个错误,它是用.NET 4修复的.但是,它似乎并没有改变语义ldtoken; 只是Reflection.Emit没有正确地发出对开放泛型方法的引用.我怀疑它也与IL汇编程序在过去甚至没有表示开放泛型方法的语法有关.
| 归档时间: |
|
| 查看次数: |
787 次 |
| 最近记录: |