[C#][.NET] メタプログラミング入門 – Reflection.Emit による Add メソッドの動的生成
※ 「[C#][.NET] メタプログラミング入門 – はじめに」の続き。
Reflection.Emit によるメタプログラミング
前回は、C#/.NET でメタプログラミングを行う方法について述べた。
これから数回に渡って、それぞれの方法について紹介していきたい。
今回は、Reflection.Emit によるメソッドの動的生成だ。
動的に生成するメソッド
簡単な例として int の足し算を行うだけのメソッドを作ってみたい。
次のようなものだ。
// 普通の静的な Add メソッド static int Add(int x, int y) { return x + y; }
Reflection.Emit では、CIL (Common Intermediate Language: 共通中間言語) を生成して、メソッド等を作成することができる。
先ずは、この Add メソッドの IL (Intermediate Language) がどのようなものかをツールを使って見てみよう。
ILSpy を使って IL を見る
アセンブリの IL は、.NET Reflector や ILSpy といったツールを使うことで見ることができる。
ILSpy は、無償で SourceForge.net の ILSpy – SharpDevelop からダウンロードして使うことができる。
例えば、次のようなコンソール アプリをビルドし、出来上がったアセンブリを ILSpy.exe で開いてみよう。
static class Program { // 普通の静的な Add メソッド static int Add(int x, int y) { return x + y; } static void Main() {} }
これを Reflection.Emit を用いて生成してみよう。
Reflection.Emit による Add メソッドの動的生成
実際にやってみると次のようになる。
using System; using System.Reflection; using System.Reflection.Emit; static class Program { // Reflection.Emit の DynamicMethod による Add メソッドの生成 static Func<int, int, int> AddByEmit() { // DynamicMethod var method = new DynamicMethod( name : "add" , returnType : typeof(int) , parameterTypes: new[] { typeof(int), typeof(int)} ); // 引数 x 生成用 var x = method.DefineParameter(position: 1, attributes: ParameterAttributes.In, parameterName: "x"); // 引数 y 生成用 var y = method.DefineParameter(position: 2, attributes: ParameterAttributes.In, parameterName: "y"); // ILGenerator var generator = method.GetILGenerator(); // 生成したい IL // IL_0000: ldarg.0 // IL_0001: ldarg.1 // IL_0002: add // IL_0003: ret // 「最初の引数をスタックにプッシュする」コードを生成 generator.Emit(opcode: OpCodes.Ldarg_0); // 「二つ目の引数をスタックにプッシュ」コードを生成 generator.Emit(opcode: OpCodes.Ldarg_1); // 「二つの値を加算する」コードを生成 generator.Emit(opcode: OpCodes.Add ); // 「リターンする」コードを生成 generator.Emit(opcode: OpCodes.Ret ); // 動的にデリゲートを生成 return (Func<int, int, int>)method.CreateDelegate(delegateType: typeof(Func<int, int, int>)); } static void Main() { var addByEmit = AddByEmit(); // デリゲートを動的に生成 var answerByEmit = addByEmit(1, 2); // 生成したデリゲートの呼び出し Console.WriteLine("answerByEmit: {0}", answerByEmit); } }
実行してみると、次のように正しく動作するのが分かるだろう。
answerByEmit: 3
まとめ
今回は、Reflection.Emit を用いて、動的にメソッドを生成するプログラムを作成した。
次回は、他の方法も試してみよう。
関連
.NET.NET, C#, Metaprogramming, Reflection.Emit, メタプログラミング
Posted by Fujiwo
関連記事
[C#][Joke] Playing C♯
※ C# Advent Calendar 2017 の12月23日の記事。 前の ...
[Event] BuriKaigi 2020 が開催されました
毎年冬に富山で開催されている BuriKaigi (*)。 今回も、90名もの方 ...
[C#][.NET] メタプログラミング入門 – 応用編 – オブジェクトの文字列変換のメタプログラミング
※ 「 メタプログラミング入門 - 応用編 - オブジェクトの文字列変換を静的/ ...
[Event] BuriKaigi 2021 を開催しました
毎年冬に富山で開催されている BuriKaigi (*)。 COVID-19 の ...
[C#][dynamic] リフレクション Q&A
「Hokuriku.NET C# メタプログラミング ~リフレクション~」に参加 ...
ディスカッション
コメント一覧
まだ、コメントがありません