C#/CIL/Reflection.Emit 问题:
我正在尝试定义一个具有函数指针的类型,实例化该类型,在另一个类型上创建一个静态方法(因为我不知道还有什么方法可以使“只是一个函数”),给出一个指向将此静态方法指向实例,稍后使用该指针调用函数。
我收效甚微。 :-(
这是类型:
Thunk = modb.DefineType("Thunk");
Thunk.DefineField("Env" , Env.AsType(), FieldAttributes.Public);
Thunk.DefineField("Expr", typeof(int), FieldAttributes.Public); // int is the correct type according to http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.ldftn.aspx
Thunk.CreateType();
到目前为止一切顺利(我认为)。然后我创建其中一个并分配函数指针:
var methodBuilder = MainType.DefineMethod("my_other_little_function", MethodAttributes.Static, typeof(Int64), new[] {Env.AsType()});
{
var il2 = methodBuilder.GetILGenerator();
il2.Emit(OpCodes.Ldarg_0);
il2.Emit(OpCodes.Stloc_0);
binding.Expr.Compile(il2);
il2.Emit(OpCodes.Ret);
}
il.Emit(OpCodes.Newobj, ThunkCtor);
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Stfld, Thunk.GetField("Env"));
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldftn, methodBuilder);
il.Emit(OpCodes.Stfld, Thunk.GetField("Expr"));
据我所知,这部分工作正常。问题出在别处,当我尝试调用它时:
var func = il.DeclareLocal(typeof(int));
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldfld, Thunk.GetField("Expr"));
il.Emit(OpCodes.Stloc, func);
il.Emit(OpCodes.Ldfld, Thunk.GetField("Env"));
il.Emit(OpCodes.Ldloc, func);
il.EmitCalli(OpCodes.Calli, CallingConventions.Standard, typeof(Int64), new[] { Env.AsType() }, null);
如果我尝试运行由此创建的程序,我会在执行任何字节码之前出错(或者至少它是这样显示的):
Unhandled Exception: System.InvalidProgramException: Common Language Runtime detected an invalid program.
如果我用代码替换 EmitCalli() 以简单地弹出函数指针和参数并压入一个数字,则程序的其余部分可以正常工作。那么我应该如何调用这个函数呢?
非常感谢。 :-)
最佳答案
除非您只是为了好玩而喜欢解决此类问题,否则另一种选择是使用库来生成所需的 IL。
Fasterflect是一个有很多反射助手的库。例如,要获取方法的委托(delegate),只需编写:
var delegate = typeof(YourClass).DelegateForCallStaticMethod( "MyStaticMethod" );
delegate( args );
该库在幕后使用 DynamicMethod 和 IL 生成,并且还具有不需要您为委托(delegate)声明和使用变量的扩展(尽管如果您打算重复调用它会更快,例如在一个紧环)。简单的变体如下所示:
var result = typeof(YourClass).CallStaticMethod( "MyStaticMethod", args );
Fasterflect 缓存生成的委托(delegate)(因为编译生成的 IL 非常昂贵),因此在简单场景中每次调用增加的性能成本等同于执行缓存查找的成本。
免责声明:我参与了上述项目。也就是说,手动编写 IL 确实不是一件有趣的任务。生成 IL 的另一个不错的选择是 Mono.Cecil 库,尽管我不熟悉它提供的内容的细节。
关于c# - 如何保存 MethodInfo 指针并稍后调用该函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14006427/