[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
関連記事
Source Code Outliner PowerToy for Visual Studio 2008
「Source Code Outliner PowerToy for Visua ...
.NET/C# 研修
今日から、.NET/C# の社内研修を始めた。 ASP.NET 研修は、ずっと前 ...
[C#][.NET] メタプログラミング入門 – 応用編 – オブジェクトの文字列変換のメタプログラミング
※ 「 メタプログラミング入門 - 応用編 - オブジェクトの文字列変換を静的/ ...
[C#][式木][LINQ] Hokuriku.NET C# 勉強会『C# 式木』(2014-10-26、金沢) のスライド公開
『Hokuriku.NET C# 勉強会『C# 式木』(2014-10-26、金 ...
[C#][.NET][Roslyn] メタプログラミング入門 – Roslyn による C# ソースコードの解析と変更
この記事は、「C# Advent Calendar 2013」の 12 月 12 ...
ディスカッション
コメント一覧
まだ、コメントがありません