次の方法で共有


式ツリー (Visual Basic)

式ツリーは、ツリーに似たデータ構造のコードを表します。各ノードは式です。たとえば、メソッド呼び出しや、 x < yなどのバイナリ操作です。

式ツリーで表されるコードをコンパイルして実行できます。 これにより、実行可能コードの動的な変更、さまざまなデータベースでの LINQ クエリの実行、動的クエリの作成が可能になります。 LINQ の式ツリーの詳細については、「 方法: 式ツリーを使用して動的クエリを作成する (Visual Basic)」を参照してください。

式ツリーは、動的言語ランタイム (DLR) でも使用され、動的言語と .NET Framework 間の相互運用性を提供し、コンパイラ ライターが共通の中間言語 (CIL) ではなく式ツリーを出力できるようにします。 DLR の詳細については、「 動的言語ランタイムの概要」を参照してください。

C# または Visual Basic コンパイラで匿名ラムダ式に基づいて式ツリーを作成することも、 System.Linq.Expressions 名前空間を使用して式ツリーを手動で作成することもできます。

ラムダ式からの式ツリーの作成

ラムダ式が Expression<TDelegate>型の変数に割り当てられると、コンパイラはラムダ式を表す式ツリーを構築するコードを出力します。

Visual Basic コンパイラでは、式ラムダ (または 1 行ラムダ) からのみ式ツリーを生成できます。 ステートメントラムダ (または複数行ラムダ) を解析することはできません。 Visual Basic でのラムダ式の詳細については、「 ラムダ式」を参照してください。

次のコード例は、ラムダ式 Function(num) num < 5を表す式ツリーを Visual Basic コンパイラで作成する方法を示しています。

Dim lambda As Expression(Of Func(Of Integer, Boolean)) =
    Function(num) num < 5

API を使用した式ツリーの作成

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

次のコード例では、API を使用して Function(num) num < 5 ラムダ式を表す式ツリーを作成する方法を示します。

' 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})

.NET Framework 4 以降では、式ツリー API は、ループ、条件付きブロック、 try-catch ブロックなどの割り当てと制御フロー式もサポートしています。 API を使用すると、Visual Basic コンパイラによってラムダ式から作成できる式ツリーよりも複雑な式ツリーを作成できます。 次の例では、数値の階乗を計算する式ツリーを作成する方法を示します。

' Creating a parameter expression.
Dim value As ParameterExpression =
    Expression.Parameter(GetType(Integer), "value")

' Creating an expression to hold a local variable.
Dim result As ParameterExpression =
    Expression.Parameter(GetType(Integer), "result")

' Creating a label to jump to from a loop.
Dim label As LabelTarget = Expression.Label(GetType(Integer))

' Creating a method body.
Dim block As BlockExpression = Expression.Block(
    New ParameterExpression() {result},
    Expression.Assign(result, Expression.Constant(1)),
    Expression.Loop(
        Expression.IfThenElse(
            Expression.GreaterThan(value, Expression.Constant(1)),
            Expression.MultiplyAssign(result,
                Expression.PostDecrementAssign(value)),
            Expression.Break(label, result)
        ),
        label
    )
)

' Compile an expression tree and return a delegate.
Dim factorial As Integer =
    Expression.Lambda(Of Func(Of Integer, Integer))(block, value).Compile()(5)

Console.WriteLine(factorial)
' Prints 120.

詳細については、「 Visual Studio 2010 での式ツリーを使用した動的メソッドの生成」を参照してください。これは、Visual Studio の新しいバージョンにも適用されます。

式ツリーの解析

次のコード例では、ラムダ式 Function(num) num < 5 を表す式ツリーを、その部分に分解する方法を示します。

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

' Create an expression tree.
Dim exprTree As Expression(Of Func(Of Integer, Boolean)) = Function(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

Console.WriteLine(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

式ツリーの不変性

式ツリーは不変である必要があります。 つまり、式ツリーを変更する場合は、既存の式ツリーをコピーし、その中のノードを置き換えることで、新しい式ツリーを構築する必要があります。 式ツリー ビジターを使用して、既存の式ツリーを走査できます。 詳細については、「 方法: 式ツリーを変更する (Visual Basic)」を参照してください。

式ツリーのコンパイル

Expression<TDelegate>型は、式ツリーで表されるコードを実行可能なデリゲートにコンパイルするCompile メソッドを提供します。

次のコード例は、式ツリーをコンパイルし、結果のコードを実行する方法を示しています。

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

' Compiling the expression tree into a delegate.
Dim result As Func(Of Integer, Boolean) = expr.Compile()

' Invoking the delegate and writing the result to the console.
Console.WriteLine(result(4))

' Prints True.

' You can also use simplified syntax
' to compile and run an expression tree.
' The following line can replace two previous statements.
Console.WriteLine(expr.Compile()(4))

' Also prints True.

詳細については、「 方法: 式ツリーを実行する (Visual Basic)」を参照してください。

こちらも参照ください