LoginSignup
43
33

More than 5 years have passed since last update.

C#のExpressionで動的コード生成

Last updated at Posted at 2017-11-12

はじめに

この記事では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として受け取り、計算しているぜ。

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

43
33
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
43
33