C#
メタプログラミング
リフレクション

はじめに

この記事ではC#のExpressionという最高にナウでヤングでイケてるライブラリについて
説明するぜ。
もし、間違ったところがあれば指摘するんだぜ。

Expressionとは?

まず、Expressionとは、式木を組み立て、コードを動的に生成することができるライブラリだぜ。
この機能を使うことで、関数電卓を作ったり、簡単なコンパイラなんかを作ることができるぜ。

式木とは?

式木はその名の通り、式の木なんだぜ。
例えば、4+5はSY5Ts.png
となるのぜ。
もっと複雑な式木を考えてみるぜ。
4+2*3
SY5Ts.png

Expression実践

じゃあ早速Expressionで4+5の式木を組み立てて見るのぜ。
Expressionはさまざまな種類があるんだが、それらは全てExpressionを継承してるんだぜ。
各種Expressionは、Expressionで定義されているstaticメソッドを使って作成するのぜ。
あっちなみにVisual Studio 2015で動作確認済みだぜ。

using System.Linq.Expressions;
namespace ExpressionQiita
{
    class Program
    {
        static void Main(string[] args)
        {
            var expr=
                Expression.Add(
                    Expression.Constant(4),
                    Expression.Constant(5)
                );
        }
    }
}

やったぜ!これで、4+5の式木が組み立てられたぜ!
じゃあ、新しく出てきた2つの関数について説明するぜ。
まずはExpression.Addの定義を紹介するぜ。

BinaryExpression Add(
    Expression left,
    Expression right
)

ほらわかるだろ?
こいつは、式を二つ受け取り、+演算を行う式を生成するのぜ。
BinaryExpressionは二項演算子を表す式のオブジェクトだぜ。

次にExpression.Constantの定義。

ConstantExpression Constant(
    object value
)

こいつは定数を表す式を表現できるのぜ。
例えば、
Expression.Constant(40);
で定数40を表現できるのぜ。

実際に実行してみよう

じゃあ、式木も作ったし、動的コード生成して、4+5の結果を取得してみよう。
残念、このままじゃ、まだだめなんだぜ。
式木はデリゲートとしてコードを生成するんだ。
つまり、関数だ。
4+5は関数じゃないから生成できないんだぜ。
じゃあ、どうするのか。
まったく簡単!
ラムダ式で包み込むのぜ!
ラムダ式は式だからね!ひゃはー!もちろん式木の仲間さ!
こうなるのぜ ()=>4+5
ラムダ式の構文がわからない?そんなもんしらんわ。
修正したコードはこうだぜ。

using System.Linq.Expressions;
using System;
namespace ExpressionQiita
{
    class Program
    {
        static void Main(string[] args)
        {
            var expr =
                //引数なし、返り値がintのラムダ式を表す
                Expression.Lambda<Func<int>>(
                    Expression.Add(
                        Expression.Constant(4),
                        Expression.Constant(5)
                    )
                );

            //動的コード生成
            Func<int> func=expr.Compile();

            //実行してみる
            Console.WriteLine(func());
        }
    }
}

新しく出てきたExpression.Lambdaの定義はこうだぜ。

LambdaExpression Lambda(
    Expression body,
    params ParameterExpression[] parameters
)

Expression.Lambda(ラムダ式に含めたい式,ラムダ式の引数)
てかんじだぜ
まあラムダ式の引数についてはすぐ後に説明するぜ。
今回は引数はとらないから省略だぜ。
このコードを実行すると()=>4+5というラムダ式を動的コード生成して、
funcに保存しているぜ。
あとはfuncはふつーにデリゲートとして使えるんだぜ。
そのあと、Console.WriteLine(func())でfuncの計算結果 9を表示しているぜ。

引数を渡そう!

毎回毎回4+5の結果を表示するだけの関数なんていらねー!
というわけで、(int x,int y)=>x+yな関数を生成するぜ。

using System.Linq.Expressions;
using System;
namespace ExpressionQiita
{
    class Program
    {
        static void Main(string[] args)
        {
            var x = Expression.Parameter(typeof(int),"x");
            var y = Expression.Parameter(typeof(int));
            var expr =
                //引数なし、返り値がintのラムダ式を表す
                Expression.Lambda<Func<int,int,int>>(
                    Expression.Add(
                        x,
                        y
                    ),x,y
                );

            //動的コード生成
            Func<int,int,int> func=expr.Compile();

            //実行してみる
            Console.WriteLine(func(4,6));
        }
    }
}

Expression.Lambda関数の第二、第三には、引数を設定してるのぜ。
こうすることで、Int型の引数を2つ受け取り、x,yに代入できるぜ。
今回の例だと、4と6を引数x,yとして受け取り、計算しているぜ。

【需要があったら続きかきます】