以下、自分のメモ書きです。
System.Reflection.Emit名前空間に存在するクラス達は、実行時に動的に型を生成するための
機能を持ちます。同じように実行時生成としては、CodeDOMもありますが、Emitは型を特定の
アセンブリ上に動的に生成する際に、直接ILコードを設定します。なのでコンパイルする手順が
省けます。その代わり、ある程度のILコードに対して知識が必要となります。
でも、実際には細かくしっていなければならない訳では決してなく(実は私もほとんど分かりません(笑))
以下のようにして、どんなILコードを設定すればいいのかを予め調べておきます。
- サンプルソースを記述する。
- 一旦それをビルド。
- 生成されたアセンブリをildasm.exeに掛けて、どんなオペコードが吐かれるのかを確認。
- 同じオペコードを実際に動的生成する型に対して設定する。
上記のようにすると、シンプルなクラスの場合は結構簡単です。
私の場合は、DevExpress社が提供しているXPOというO/Rマッピングライブラリにて
利用するクラスを動的生成したかっただけなので、これで事足りそうな感じがしています。
実際の各クラスの役割や使い方などはMSDNの方が断然詳しいのでそれは割愛しておいて
サンプルみた方が分かりやすいと思います。
以下、サンプルです。
#region Emitのサンプル public class EmitSample : IExecutable{ public interface ISayHello{ void SayHello(); } public void Execute(){ // // 0.これから作成する型を格納するアセンブリ名作成. // AssemblyName asmName = new AssemblyName{Name="DynamicTypes"}; // // 1.AssemlbyBuilderの生成 // AppDomain domain = AppDomain.CurrentDomain; AssemblyBuilder asmBuilder = domain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run); // // 2.ModuleBuilderの生成. // ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule("HelloWorld"); // // 3.TypeBuilderの生成. // TypeBuilder typeBuilder = modBuilder.DefineType("SayHelloImpl", TypeAttributes.Public, typeof(object), new Type[]{typeof(ISayHello)}); // // 4.MethodBuilderの生成 // MethodAttributes methodAttr = (MethodAttributes.Public | MethodAttributes.Virtual); MethodBuilder methodBuilder = typeBuilder.DefineMethod("SayHello", methodAttr, typeof(void), new Type[]{}); typeBuilder.DefineMethodOverride(methodBuilder, typeof(ISayHello).GetMethod("SayHello")); // // 5.ILGeneratorを生成し、ILコードを設定. // ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ldstr, "Hello World"); il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[]{ typeof(string) })); il.Emit(OpCodes.Ret); // // 6.作成した型を取得. // Type type = typeBuilder.CreateType(); // // 7.型を具現化. // ISayHello hello = (ISayHello) Activator.CreateInstance(type); // // 8.実行. // hello.SayHello(); } } #endregion
上記のものも、作成する際は一旦ISayHelloインターフェースを実装したクラスをサンプルとして
作成してビルドし、そのILコードを確認してからそのままEmitしただけです。
参考にしているリソースは以下です。
- http://www.codeproject.com/KB/cs/DynamicCodeGeneration2.aspx
- http://www.codeproject.com/KB/dotnet/Creating_Dynamic_Types.aspx
- http://www.codeproject.com/KB/dotnet/Creating_Dynamic_Types2.aspx
- http://www.atelier-blue.com/program/il/
- http://www.codeguru.com/csharp/.net/net_general/il/article.php/c4635/