4

コードからコードを動的にコンパイルします。

            string code = @"
                namespace CodeInjection
                {
                    public static class DynConcatenateString
                    {
                        public static string Concatenate(string s1, string s2){
                            return s1 + "" ! "" + s2;
                        }
                    }
                }";

            // http://stackoverflow.com/questions/604501/generating-dll-assembly-dynamically-at-run-time
            Console.WriteLine("Now doing some injection...");

            Console.WriteLine("Creating injected code in memory");


            CSharpCodeProvider codeProvider = new CSharpCodeProvider();
            ICodeCompiler icc = codeProvider.CreateCompiler();
            CompilerParameters parameters = new CompilerParameters();
            parameters.GenerateExecutable = false;
            parameters.GenerateInMemory = true;
            //parameters.OutputAssembly = "DynamicCode.dll"; // if specified creates the DLL
            CompilerResults results = icc.CompileAssemblyFromSource(parameters, code);

次に、リフレクションを使用してメソッドを呼び出すことができます。

                Console.WriteLine("Input two strings, and I will concate them with reflection:");
                var s1 = Console.ReadLine();
                var s2 = Console.ReadLine();
                var result = (string)results.CompiledAssembly.GetType("CodeInjection.DynConcatenateString").GetMethod("Concatenate").Invoke(null, new object[] { s1, s2 });

                Console.WriteLine();
                Console.WriteLine("Result:");
                Console.WriteLine(result);

しかし、私は次のようなものを呼び出したいと思います:

                Console.WriteLine("Input two strings, and I will concate them with dynamic type:");
                var s1 = Console.ReadLine();
                var s2 = Console.ReadLine();

                dynamic type = results.CompiledAssembly.GetType("CodeInjection.DynConcatenateString");
                var resultA = (string)type.Concatenate(s1, s2); // runtime error
                // OR
                var resultB = (string)CodeInjection.DynConcatenateString.Concatenate(s1, s2); // compile error (cannot find assembly)


                Console.WriteLine();
                Console.WriteLine("Result:");
                Console.WriteLine(resultA);
                Console.WriteLine(resultB);

結果Bの方が良いでしょう。それを行う方法はありますか?厳密には .NET 4.0 が必要です。まだ 4.5 に更新していません (チームの半数が VS 2010 を使用しているため)。(リフレクションで呼び出すことができます。dyn.コードをテストする必要があるため、別の方法を探しているだけです)

4

4 に答える 4

2

メソッドを呼び出していますstatic。チェックをバイパスしますが、実際にはfordynamicを呼び出そうとしています。Concatenate()System.TypeCodeInjection.DynConcatenateString

まず、インスタンス メソッドにします。

public class DynConcatenateString
{
    public string Concatenate(string s1, string s2){
        return s1 + "" ! "" + s2;
    }
}

コードを見てみましょう:

dynamic type = results.CompiledAssembly.GetType("CodeInjection.DynConcatenateString");

これは でありSystem.Type、タイプ のオブジェクトではありませんCodeInjection.DynConcatenateString。に変更dynamicするvarと、コンパイル時に正しい型が表示されます。次のように、そのタイプのインスタンスを作成する必要があります。

var type = results.CompiledAssembly.GetType("CodeInjection.DynConcatenateString");
dynamic instance = Activator.CreateInstance(type);

CodeInjection.DynConcatenateString構文 B の場合、コンパイル時に存在しないため、C# には希望がありません。その行は失敗します。

静的に保持する必要がある場合は、リフレクションを使用してそのメソッドを呼び出すことしかできません (その場合は役に立ちませんdynamic)。パフォーマンスへの影響について心配する必要はありません...DLR はプレーンなリフレクションよりもはるかに高速ではありません (私の知る限り、キャッシングのタッチで実装されている方法です)。

于 2013-06-04T13:14:02.727 に答える
0

ジェネリック型を使用しないのはなぜですか? クラス インターフェイスを定義します。


    public interface IDynConcatenateString 
    {
        string Concatenate(string s1, string s2);
    }

そして、動的コードを生成します

    public T GetInstanceOf<T>(string code, string typename)
    {
        Console.WriteLine("Now doing some injection...");

        Console.WriteLine("Creating injected code in memory");


        CSharpCodeProvider codeProvider = new CSharpCodeProvider();
        ICodeCompiler icc = codeProvider.CreateCompiler();
        CompilerParameters parameters = new CompilerParameters();
        parameters.GenerateExecutable = false;
        parameters.GenerateInMemory = true;
        //parameters.OutputAssembly = "DynamicCode.dll"; // if specified creates the DLL
        CompilerResults results = icc.CompileAssemblyFromSource(parameters, code);

        //type name = "CodeInjection.DynConcatenateString"

        T codeclass = (T)results.CompiledAssembly.CreateInstance(typename);

        return codeclass;

    }

このように実行してみてください...

public void Exec() 
    {
        string code = @"
            namespace CodeInjection
            {
                public class MyDynConcatenateString : IDynConcatenateString 
                {
                    public string Concatenate(string s1, string s2){
                        return s1 + "" ! "" + s2;
                    }
                }
            }";
        IDynConcatenateString writer = GetInstanceOf<IDynConcatenateString>(
            code, "CodeInjection.MyDynConcatenateString");

        var s1 = Console.ReadLine();
        var s2 = Console.ReadLine();
        var result = writer.Concatenate(s1, s2);

        Console.WriteLine(result);

    }

IDynConcatenateString の実装は動的であり、Exec メソッドのパラメーターとして "code" 変数で定義されます。インターフェイスを定義するだけでよく、メソッド名やクラス名をハードコーディングする必要はありません。

于 2013-06-04T14:27:41.110 に答える