我正在使用Reflection.Emit创建一个程序集,我希望它能够调用一个特殊的回调。
以下是代码的简化版本:
public void Call(ILGenerator il, Delegate action)
{
il.Emit(OpCodes.Call, action.Method);
}
public static void DoStuff()
{
Console.WriteLine("Action invoked!");
}
Call(CurrentMethod.ILGenerator, DoStuff);
此代码的工作方式与预期一致。
但是,我想传递一个lambda表达式,如下所示:
Call(CurrentMethod.ILGenerator, () => Console.WriteLine("test"));
这次抛出以下异常:
System.MethodAccessException:尝试按方法'.Run()'访问方法'Compiler.Test.ImportedFunctions.b__0()'失败。
有办法解决它吗?
答案 0 :(得分:1)
Delegate
它太通用了。试试Action
。
但是要警告!
如果委托的target属性不为null,则无法执行此操作。
您可以通过将目标值暂时存储在静态字段中来解决此问题。
可能的解决方案(发出修饰符):
class Foo { static object target; }
public void Call(ILGenerator il, Action action)
{
Foo.target = action.Target;
il.Emit(OpCodes.Ldsfld, typeof(Foo).GetField("target");
il.Emit(OpCodes.Callvirt, action.Method);
}
如果您在没有递归调用的单线程环境中运行,那么这将起作用。
对于递归环境,您需要使用Foo.target
的动态绑定,这在C#中不可用。
幸运的是I have written such a facility已经是C#了。