式ツリー
更新 : 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 など、特定の型のツリー ノードを作成する静的ファクトリ メソッドが含まれています。ParameterExpression や MethodCallExpression などの式固有の式ツリー型も、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 を取得できます。 |