1

我正在使用 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()”失败。

有没有办法解决它?

4

1 回答 1

1

Delegate它太笼统了。试试Action

但请注意!

如果委托的目标属性不为空,则这是不可能的。

您可以通过将目标值临时存储在静态字段中来解决此问题。

可能的解决方案(发出的修饰符):

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# 中不可用。

幸运的是,我已经为 C# 编写了这样的工具。

于 2013-03-20T17:37:48.593 回答