2013-08-22 111 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