【问题标题】:C# calling external method (delegate) from withinC# 从内部调用外部方法(委托)
【发布时间】:2013-08-23 22:32:31
【问题描述】:

我正在使用 as described here 在 C# 程序中生成和执行 C#。

如你所见,可以通过classType.GetMethod("Execute").Invoke(instance, args)调用编译后代码的“Execute”方法。

变量args 是要传递给Execute 方法的参数对象数组。使用这个系统,我已经能够相对容易地传递事情并且没有问题。

现在这是一个大问题...我需要传递一个回调函数(例如一个委托),以便Execute 方法能够向主程序发出信号。我一直在尝试传递与签名匹配的类型化委托,但它失败了(甚至不会运行)。接下来,我尝试传递一个 Delegate 而不指定也失败的类型(这次它在尝试调用时失败)。我还尝试将它作为普通对象传递,然后将其转换回生成的代码中,但它并没有做任何不同的事情。

由于我不太喜欢 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();

【问题讨论】:

  • 你应该发布不起作用的代码。
  • 您必须向我们展示传入委托的代码以及您正在编译的试图执行该委托的代码。其中一个或两个都可能是问题所在。
  • 好的,好的,我看看我能做什么......

标签: c# delegates anonymous-function


【解决方案1】:

您必须传入不同类型的委托,然后从新编译的代码内部对其进行转换。

例如,在代码之外,您可以像这样调用它:

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

现在您有几个选项来处理如何从编译的代码中处理这个问题。

首先,您可以放弃定义自己的 LoggerInternal 委托类型,而只需使用 Action&lt;string, string&gt;

其次,在编译后的代码中,你可以通过这种类型转换委托:

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);
}

【讨论】:

  • 这看起来很合理...我一回来工作就试试这个。 :D
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-01
  • 2017-11-24
  • 2014-08-28
相关资源
最近更新 更多