从反射生成的程序集中调用 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的主要内容,如果未能解决你的问题,请参考以下文章
如何从应用程序域中所有加载的程序集中获取所有静态类并使用反射调用静态方法