代码之家  ›  专栏  ›  技术社区  ›  Impworks

从反射生成的程序集调用lambda

  •  1
  • Impworks  · 技术社区  · 11 年前

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

    有办法解决这个问题吗?

    1 回复  |  直到 11 年前
        1
  •  1
  •   leppie    11 年前

    Delegate 它太通用了。尝试 Action .

    但请注意!

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

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

    可能的解决方案(发射的修改器):

    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#已经。