2013-03-20 37 views
1

我正在使用Reflection.Emit创建程序集,我希望它能调用特殊的回调函数。从反射生成的程序集调用lambda

下面的代码的简化版本:

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

代码是否完全信任? – Greg 2013-03-20 17:33:10

+0

@Greg,程序集是使用'AppDomain.CurrentDomain.DefineDynamicAssembly(名称,AssemblyBuilderAccess.RunAndSave)'创建的。如何检查信任设置? – Impworks 2013-03-20 17:43:45

+0

@Impworks:如果你能做到这一点,那么你已经完全信任:) – leppie 2013-03-20 17:48:14

回答

1

Delegate它太泛化了。尝试Action

但是警告!

如果委托的目标属性不为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#了。

+0

不幸的是,从lambdas创建的'Func <>'和'Action <>'对象不是静态的。我会给你的设施一个尝试。 – Impworks 2013-03-20 17:58:16

+1

只有代表捕获变量时,它才是非静态的。 – leppie 2013-03-20 18:05:15