読者です 読者をやめる 読者になる 読者になる

プログラミング C# - 翔ソフトウェア (Sho's)

C#/.NET/ソフトウェア開発など

メタプログラミング入門 - 式木による Add メソッドの動的生成

Metasequoia

※ 「[C#][.NET] メタプログラミング入門 - Reflection.Emit による Add メソッドの動的生成」の続き。

式木によるメタプログラミング

前回は、Reflection.Emit を用いて Add メソッドを動的生成するプログラムを作成した。

今回は、式木によるメソッドの動的生成だ。

動的に生成するメソッド

今回も次の Add メソッドを生成する。

    // 普通の静的な Add メソッド
    static int Add(int x, int y)
    {
        return x + y;
    }

前回は、ILSpy で IL を調べ、それを参考にしたた。

今回は式木として生成するため、先ずは Add メソッドにあたる式を作り、その構造を見て参考にしよう。

以前、「Expression の構造を調べてみる」で行ったように、

using System;
using System.Linq.Expressions;

class Program
{
    static void Main()
    {
        Expression<Func<int, int, int>> add = (x, y) => x + y;
    }
}

のようなプログラムを作成し、デバッグ実行で、add の構造を調べてみよう。

Visual Studio のデバッガーの「クイックウォッチ」の表示から一部抜粋

Visual Studio のデバッガーで add 式の構造を見る (一部抜粋)
Visual Studio のデバッガーで add 式の構造を見る (一部抜粋)

これを見ると、次のような構造をしていることが分かる。

add 式の構造
add 式の構造

これを式木を用いて生成してみよう。

式木による Add メソッドの動的生成

実際にやってみると次のようになる。

using System;
using System.Linq.Expressions;

static class Program
{
    // Expression (式) による Add メソッドの生成
    static Func<int, int, int> AddByExpression()
    {
        // 生成したい式
        // (int x, int y) => x + y

        var x      = Expression.Parameter(type: typeof(int)); // 引数 x の式
        var y      = Expression.Parameter(type: typeof(int)); // 引数 y の式
        var add    = Expression.Add      (left: x, right: y); // x + y の式
        var lambda = Expression.Lambda   (add, x, y        ); // (x, y) => x + y の式
        // ラムダ式をコンパイルしてデリゲートとして返す
        return (Func<int, int, int>)lambda.Compile();
    }

    static void Main()
    {
        var addByExpression    = AddByExpression();     // デリゲートを動的に生成
        var answerByExpression = addByExpression(1, 2); // 生成したデリゲートの呼び出し
        Console.WriteLine("answerByExpression: {0}", answerByExpression);
    }
}

Reflection.Emit を使った場合と比較すると、やや簡潔に書けるのが分かるだろう。

実行してみると、次のように正しく動作する。

answerByExpression: 3

まとめ

今回は、式木を用いて、動的にメソッドを生成するプログラムを作成した。

次回は、更に他の方法も試してみよう。