0

ここで説明されているように、C# プログラム内から C# を生成して実行しています。

ご覧のとおり、コンパイルされたコードの「実行」メソッドを 経由で呼び出すことができますclassType.GetMethod("Execute").Invoke(instance, args)

変数は、メソッド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();
4

1 に答える 1

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);
}
于 2013-08-23T14:32:31.610 に答える