2013-03-20 18 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

相關問題