式ツリー

更新 : 2007 年 11 月

式ツリーは、言語レベル コードをデータの形式で表します。データは、ツリー状の構造で格納されます。式ツリーの各ノードは式を表します。たとえば、メソッド呼び出しや x < y といった二項演算などです。

次の図に、式の例と、それを式ツリーの形で表した例を示します。式の各部分の色は、式ツリー内の式ツリー ノードの色に対応しています。式ツリー ノードのさまざまな型も示しています。

式ツリーのダイアグラム

次のコード例では、ラムダ式 num => num < 5 (C#) または Function(num) num < 5 (Visual Basic) を表す式ツリーを各部分に分解する方法を示します。

' Import the following namespace to your project: System.Linq.Expressions

' Create an expression tree.
Dim exprTree As Expression(Of Func(Of Integer, Boolean)) = Function(ByVal num) num < 5

' Decompose the expression tree.
Dim param As ParameterExpression = exprTree.Parameters(0)
Dim operation As BinaryExpression = exprTree.Body
Dim left As ParameterExpression = operation.Left
Dim right As ConstantExpression = operation.Right

MsgBox(String.Format("Decomposed expression: {0} => {1} {2} {3}", _
                  param.Name, Left.Name, operation.NodeType, Right.Value))

' This code produces the following output:
'
' Decomposed expression: num => num LessThan 5

// Add the following using directive to your code file:
// using System.Linq.Expressions;

// Create an expression tree.
Expression<Func<int, bool>> exprTree = num => num < 5;

// Decompose the expression tree.
ParameterExpression param = (ParameterExpression)exprTree.Parameters[0];
BinaryExpression operation = (BinaryExpression)exprTree.Body;
ParameterExpression left = (ParameterExpression)operation.Left;
ConstantExpression right = (ConstantExpression)operation.Right;

Console.WriteLine("Decomposed expression: {0} => {1} {2} {3}",
                  param.Name, left.Name, operation.NodeType, right.Value);

/*  This code produces the following output:

    Decomposed expression: num => num LessThan 5
*/

式ツリーの作成

System.Linq.Expressions 名前空間は、式ツリーを手作業で作成するための API を提供します。Expression クラスには、名前付きのパラメータ式を表す ParameterExpression や、メソッド呼び出しを表す MethodCallExpression など、特定の型のツリー ノードを作成する静的ファクトリ メソッドが含まれています。ParameterExpressionMethodCallExpression などの式固有の式ツリー型も、System.Linq.Expressions 名前空間で定義されます。これらの型は Expression 抽象型から派生したものです。

コンパイラにより、自動的に式を作成することもできます。コンパイラにより生成された式ツリーは、常に Expression<TDelegate> 型のノードをルートとします。つまり、この式ツリーのルート ノードはラムダ式を表します。

次のコード例では、ラムダ式 num => num < 5 (C#) または Function(num) num < 5 (Visual Basic) を表す式ツリーを 2 つの方法で作成します。

' Import the following namespace to your project: System.Linq.Expressions

' Manually build the expression tree for the lambda expression num => num < 5.
Dim numParam As ParameterExpression = Expression.Parameter(GetType(Integer), "num")
Dim five As ConstantExpression = Expression.Constant(5, GetType(Integer))
Dim numLessThanFive As BinaryExpression = Expression.LessThan(numParam, five)
Dim lambda1 As Expression(Of Func(Of Integer, Boolean)) = _
  Expression.Lambda(Of Func(Of Integer, Boolean))( _
        numLessThanFive, _
        New ParameterExpression() {numParam})

' Let the compiler generate the expression tree for
' the lambda expression num => num < 5.
Dim lambda2 As Expression(Of Func(Of Integer, Boolean)) = Function(ByVal num) num < 5

// Add the following using directive to your code file:
// using System.Linq.Expressions;

// Manually build the expression tree for 
// the lambda expression num => num < 5.
ParameterExpression numParam = Expression.Parameter(typeof(int), "num");
ConstantExpression five = Expression.Constant(5, typeof(int));
BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);
Expression<Func<int, bool>> lambda1 =
    Expression.Lambda<Func<int, bool>>(
        numLessThanFive,
        new ParameterExpression[] { numParam });

// Let the compiler generate the expression tree for
// the lambda expression num => num < 5.
Expression<Func<int, bool>> lambda2 = num => num < 5;

式ツリーの不変性

式ツリーは変更できません。つまり、式ツリーを変更するには、既存の式ツリーをコピーしてそれを変更することで、新しい式ツリーを作成する必要があります。式ツリー ビジタを使用して、既存の式ツリーを走査することができます。詳細については、「方法 : 式ツリー ビジタを実装する」および「方法 : 式ツリーを変更する」を参照してください。

ラムダ式

ラムダ式が Expression<TDelegate> 型の変数に割り当てられている場合、コンパイラはラムダ式を表す式ツリーを出力します。たとえば、Queryable クラスで定義されている一部の標準クエリ演算子メソッドには、Expression<TDelegate> 型のパラメータがあります。これらのメソッドを呼び出してラムダ式を渡すと、コンパイラにより式ツリーが生成されます。

Expression<TDelegate> 型に含まれる Compile メソッドにより、式ツリーの表すコードを実行可能なデリゲートにコンパイルします。この実行可能コードは、ラムダ式をデリゲート型に割り当てることで生成される実行可能コードと同じです。

メモ :

実行可能コードにコンパイルできるのは、機能を表す式ツリー、つまり Expression<TDelegate> およびその親の LambdaExpression 型のみです。他の型の式ツリーを実行するには、まずそれを LambdaExpression ノード内にラップする必要があります。LambdaExpression メソッドを呼び出し、引数として式ツリーを渡すことで、そのような Lambda を取得できます。

参照

処理手順

方法 : 式ツリーを実行する

方法 : 式ツリーを変更する

方法 : 式ツリー ビジタを実装する

概念

LINQ の式ツリー

ラムダ式

参照

ラムダ式 (C# プログラミング ガイド)

System.Linq.Expressions