2013-08-22 109 views
0

我從C#程序使用as described here生成和執行C#。您可以看到,可以通過classType.GetMethod("Execute").Invoke(instance, args)調用編譯代碼的「Execute」方法。C#調用外部方法(委託)從

變量args是要傳遞給Execute方法的參數的對象數組。我已經能夠使用這個系統相對容易且沒有問題地傳遞事物。

現在這裏是一個大問題......我需要傳遞一個回調函數(例如一個委託),以便Execute方法能夠向主程序發送信號。我一直試圖傳遞一個與簽名匹配的類型化委託,但它失敗了(甚至不會運行)。接下來,我嘗試傳遞一個委託,但沒有指定也失敗的類型(這次嘗試調用時失敗)。我也嘗試將它作爲普通對象傳遞並將其轉換回生成的代碼中,但它沒有做任何不同的事情。

由於我對C#沒有太多的瞭解,我認爲我錯過了一些非常基本的東西。另外,我沒有一個有效的測試用例代碼...但它應該不會太困難與我上面提供的鏈接工作..

參見:http://support.microsoft.com/kb/304655

編輯:這是一些示例代碼:

class CompilerTest { 

    private object obj; 
    private MethodInfo mtd; 

    public void on_log(string type, string message){ 
     MessageBox.Show(type.ToUpper() + ": " + message); 
    } 

    public void compile(){ 
     CodeDomProvider c = CodeDomProvider.CreateProvider("CSharp"); 
     CompilerParameters cp = new CompilerParameters(); 

     cp.ReferencedAssemblies.Add("system.dll"); 
     cp.ReferencedAssemblies.Add("system.data.dll"); 
     cp.ReferencedAssemblies.Add("system.windows.forms.dll"); 

     cp.CompilerOptions = "/t:library"; 
     cp.GenerateInMemory = true; 

     StringBuilder sb = new StringBuilder(""); 
     sb.AppendLine("using System;"); 
     sb.AppendLine("using System.Data;"); 
     sb.AppendLine("using System.Reflection;"); 
     sb.AppendLine("using System.Windows.Forms;"); 

     sb.AppendLine("public delegate void LoggerInternal(string type, string message);"); 

     sb.AppendLine("public class CSCodeEvalCls{"); 

     sb.AppendLine(" private LoggerInternal log;"); 

     sb.AppendLine(" public void E(object lgr){"); 
     sb.AppendLine(" this.log = (RuleLoggerInternal)lgr;"); 
     sb.AppendLine(" }"); 

     sb.AppendLine(" private void L(string type, string message){"); 
     sb.AppendLine(" this.log(type, message);"); 
     sb.AppendLine(" }"); 

     sb.AppendLine("}"); 

     CompilerResults cr = c.CompileAssemblyFromSource(cp, sb.ToString()); 
     System.Reflection.Assembly a = cr.CompiledAssembly; 

     this.obj = a.CreateInstance("CSCodeEvalCls"); 
     this.mtd = this.obj.GetType().GetMethod("E"); 
    } 

    public void execute(){ 
     this.mtd.Invoke(this.obj, new object[]{ this.on_log }); 
    } 

} 

CompilerTest test = new CompilerTest(); 
test.compile(); 
test.execute(); 
+3

您應該發佈不起作用的代碼。 –

+4

您必須向我們展示通過代理傳遞的代碼以及您正在嘗試執行該代理的即時編譯代碼。其中一個或兩個都可能是問題所在。 – cdhowie

+0

好的,好吧,我會看看我能做些什麼...... – Christian

回答

1

您必須傳入不同類型的委託,然後將其從新編譯的代碼中轉換。

例如,代碼之外,你會調用它是這樣的:

this.mtd.Invoke(this.obj, new object[]{ new Action<string, string>(this.on_log) }); 

現在你對你如何從你的編譯代碼處理這幾個選項。

首先,您可以放棄定義自己的LoggerInternal委託類型,並只使用Action<string, string>

其次,編譯後的代碼裏面,你可以通過這種類型的委託轉換:

public void E(object lgr) { 
    this.log = new LoggerInternal((Action<string, string>)lgr); 
} 

第三,如果你不希望編譯代碼知道什麼樣的委託它獲得通過,就可以使用Delegate.CreateDelegate()

public void E(object lgr) { 
    Delegate d = (Delegate)lgr; 

    this.log = (LoggerInternal)Delegate.CreateDelegate(
     typeof(LoggerInternal), 
     d.Target, 
     d.Method); 
} 
+0

這看起來很合理......我一回到工作崗位就會嘗試。 :d – Christian