2011-01-17 3 views
7

動的に生成されたC#コードをコンパイルして実行するには、どのようにC#コードを記述できますか。周囲に例がありますか?C#を使用してコードを動的にコンパイル

私が行ったのは、C#クラス(またはクラス)を動的に構築し、実行時に実行することです。私は生成されたクラスが動的ではない他のC#クラスとやり取りするようにします。

exeファイルまたはdllファイルを生成する例があります。私はそれ以来、私はちょうどそれがメモリ内のいくつかのC#のコードをコンパイルして、それを実行したい。たとえば、だからここ

が動的ではないクラスで、それが私のC#のアセンブリで定義され、唯一
public class NotDynamicClass 
{ 
    private readonly List<string> values = new List<string>(); 

    public void AddValue(string value) 
    { 
     values.Add(value); 
    } 

    public void ProcessValues() 
    { 
     // do some other stuff with values 
    } 
} 

がここに動的である私のクラスである、コンパイル時に変更されます。私のC#のコードは、このクラスを生成し、それを実行し、

public class DynamicClass 
{ 
    public static void Main() 
    { 
     NotDynamicClass class = new NotDynamicClass(); 

     class.AddValue("One"); 
     class.AddValue("two"); 
    } 
} 

ますので、結果は最後に私の非動的なコードがProcessValuesを呼ぶだろうし、それはいくつかの他のものを行うだろうということです。動的コードのポイントは、私たちまたはクライアントがカスタムロジックをソフトウェアに追加できるようにすることです。

ありがとうございました。

+2

「プラグイン」アセンブリをコンパイルし、動的にコンパイルする代わりに実行時にそれらのプラグインをロードすることは可能でしょうか? –

+0

そうです、私は別のプロジェクトの前にそれをしました。それは可能ですが、このプロジェクトのために私たちが何をしているのかは実際には分かりません。私はそれを考慮する、ありがとう。 – peter

答えて

15

2つの可能性:

  1. Reflection.Emit
  2. System.CodeDom.Compiler

UPDATE:

コメント欄での要求として、ここでReflection.Emitの使用方法を示す完全な例です動的にクラスを構築し、スタティを追加するそれにCメソッド:

using System; 
using System.Collections.Generic; 
using System.Reflection; 
using System.Reflection.Emit; 

public class NotDynamicClass 
{ 
    private readonly List<string> values = new List<string>(); 

    public void AddValue(string value) 
    { 
     values.Add(value); 
    } 

    public void ProcessValues() 
    { 
     foreach (var item in values) 
     { 
      Console.WriteLine(item); 
     } 
    } 
} 

class Program 
{ 
    public static void Main() 
    { 
     var assemblyName = new AssemblyName("DynamicAssemblyDemo"); 
     var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); 
     var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, false); 
     var typeBuilder = moduleBuilder.DefineType("DynamicClass", TypeAttributes.Public); 

     var methodBuilder = typeBuilder.DefineMethod(
      "Main", 
      MethodAttributes.Public | MethodAttributes.Static, 
      null, 
      new Type[0] 
     ); 

     var il = methodBuilder.GetILGenerator(); 
     var ctor = typeof(NotDynamicClass).GetConstructor(new Type[0]); 
     var addValueMi = typeof(NotDynamicClass).GetMethod("AddValue"); 
     il.Emit(OpCodes.Newobj, ctor); 
     il.Emit(OpCodes.Stloc_0); 
     il.DeclareLocal(typeof(NotDynamicClass)); 
     il.Emit(OpCodes.Ldloc_0); 
     il.Emit(OpCodes.Ldstr, "One"); 
     il.Emit(OpCodes.Callvirt, addValueMi); 
     il.Emit(OpCodes.Ldloc_0); 
     il.Emit(OpCodes.Ldstr, "Two"); 
     il.Emit(OpCodes.Callvirt, addValueMi); 
     il.Emit(OpCodes.Ldloc_0); 
     il.Emit(OpCodes.Callvirt, typeof(NotDynamicClass).GetMethod("ProcessValues")); 
     il.Emit(OpCodes.Ret); 
     var t = typeBuilder.CreateType(); 
     var mi = t.GetMethod("Main"); 
     mi.Invoke(null, new object[0]); 
    } 
} 

あなたがいないNotDynamicClassメソッド内のブレークポイントを入れて、それらが呼び出されますどのように見ることができました。 UPDATE 2


は、ここでのCodeDOMコンパイラとの例を示します

using System; 
using System.CodeDom.Compiler; 
using System.Collections.Generic; 
using Microsoft.CSharp; 

public class NotDynamicClass 
{ 
    private readonly List<string> values = new List<string>(); 

    public void AddValue(string value) 
    { 
     values.Add(value); 
    } 

    public void ProcessValues() 
    { 
     foreach (var item in values) 
     { 
      Console.WriteLine(item); 
     } 
    } 
} 

class Program 
{ 
    public static void Main() 
    { 
     var provider = CSharpCodeProvider.CreateProvider("c#"); 
     var options = new CompilerParameters(); 
     var assemblyContainingNotDynamicClass = Path.GetFileName(Assembly.GetExecutingAssembly().Location); 
     options.ReferencedAssemblies.Add(assemblyContainingNotDynamicClass); 
     var results = provider.CompileAssemblyFromSource(options, new[] 
     { 
@"public class DynamicClass 
{ 
    public static void Main() 
    { 
     NotDynamicClass @class = new NotDynamicClass(); 
     @class.AddValue(""One""); 
     @class.AddValue(""Two""); 
     @class.ProcessValues(); 
    } 
}" 
     }); 
     if (results.Errors.Count > 0) 
     { 
      foreach (var error in results.Errors) 
      { 
       Console.WriteLine(error); 
      } 
     } 
     else 
     { 
      var t = results.CompiledAssembly.GetType("DynamicClass"); 
      t.GetMethod("Main").Invoke(null, null); 
     } 
    } 
} 
+0

私は上記のやりたいことに対応してあなたが推奨する良い例はありますか? – peter

+0

@peter、更新情報をご覧ください。私は、実行時にメソッドを追加し、最後にそれらのメソッドを呼び出すことによって、クラスを動的に構築する方法を示す例を追加しました。 –

+0

ありがとうございました。それは私が恐れていたことと私が他の場所で見たことです。あなたはGetILGeneratorを使い、il.Emitなどを使ってメソッドを構築しています。コードを書くだけの方法はありません。コードを持つ文字列を指定し、上記の2番目のコード例のように '実行する'その理由は、これらのスクリプトを「テキスト」として書き込んでDBに格納したいからです。 – peter

2

モノが(もちろん、Linuxのと一緒に)は、Windows上で.NETアプリケーションで使用可能ですC# compiler as a serviceを持っています。

関連する問題