System.Reflection.Emit名前空間のTypeBuilderやMethodBuilderなどのクラスを使うと型情報やメソッドの実装を動的に生成し、実行することができます。 ただし、メソッドの実装にはILGeneratorクラスを使ってILコード(intermediate language, 中間言語コード)を記述する必要があるため、ILに関する知識が必要となります。
以下の例ではSystem.Reflection.Emit名前空間のクラスを使って以下のようなクラスを動的に生成し、作成したクラスのメソッドを呼び出しています。
System.Reflection.Emit名前空間のクラスを使って動的にクラスとメソッドを生成する
using System;
using System.Reflection;
using System.Reflection.Emit;
class Sample {
static void Main()
{
// アセンブリ名"DynamicAssmembly"で動的にアセンブリを生成する
var assmName = new AssemblyName("DynamicAssmembly");
AssemblyBuilder assm = AppDomain.CurrentDomain.DefineDynamicAssembly(assmName, AssemblyBuilderAccess.Run);
// 作成したアセンブリ内にモジュールを宣言する
var module = assm.DefineDynamicModule("DynamicModule");
// 作成したモジュール内にクラス(object型を基底クラスとした型)を宣言する
var type = module.DefineType("HelloWorld", TypeAttributes.Public, typeof(object));
// 作成したクラス内に戻り値がvoid(なし)、引数なしのパブリックメソッドを宣言する
var method = type.DefineMethod("Print", MethodAttributes.Public, typeof(void), Type.EmptyTypes);
// メソッドの実装となるILコードを生成する
var generator = method.GetILGenerator();
generator.Emit(OpCodes.Ldstr, "Hello, world!");
generator.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new[] {typeof(string)}));
generator.Emit(OpCodes.Ret);
// 生成した型情報を使ってインスタンスを作成し、メソッドを呼び出す
var t = type.CreateType();
var inst = Activator.CreateInstance(t);
t.InvokeMember("Print", BindingFlags.InvokeMethod, null, inst, null);
}
}
実行結果
Hello, world!