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

Posted

技术标签:

【中文标题】从反射生成的程序集中调用 lambda【英文标题】:Calling a lambda from Reflection-generated assembly 【发布时间】:2013-03-20 17:28:28 【问题描述】:

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

有办法解决吗?

【问题讨论】:

代码是否在完全信任下运行? @Greg,程序集是使用AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave) 创建的。如何检查信任设置? @Impworks:如果你能做到,那么你已经在完全信任下运行了 :) 【参考方案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# 中不可用。

幸运的是 I have written such a facility 已经用于 C#。

【讨论】:

不幸的是,从 lambdas 创建的 Func<>Action<> 对象不是静态的。我会试试你的设施。 只有在委托捕获变量时它才是非静态的。

以上是关于从反射生成的程序集中调用 lambda的主要内容,如果未能解决你的问题,请参考以下文章

如何从应用程序域中所有加载的程序集中获取所有静态类并使用反射调用静态方法

通过反射从加载的程序集中返回 Types[] 时的 FileNotFound

什么叫做反射,反射在编程中起什么作用?

C#通过反射获取不同命名空间下的类(属性和方法)

C#使用反射加载多个程序集

学习--反射