Drzewa wyrażeń (Visual Basic)
Drzewa wyrażeń reprezentują kod w strukturze danych przypominającej drzewo, gdzie każdy węzeł jest wyrażeniem, na przykład wywołaniem metody lub operacją binarną, taką jak x < y
.
Możesz skompilować i uruchomić kod reprezentowany przez drzewa wyrażeń. Umożliwia to dynamiczną modyfikację kodu wykonywalnego, wykonywanie zapytań LINQ w różnych bazach danych oraz tworzenie zapytań dynamicznych. Aby uzyskać więcej informacji na temat drzew wyrażeń w LINQ, zobacz How to: Use Expression Trees to Build Dynamic Queries (Visual Basic)( Jak używać drzew wyrażeń do tworzenia dynamicznych zapytań (Visual Basic).
Drzewa wyrażeń są również używane w środowisku uruchomieniowym języka dynamicznego (DLR) w celu zapewnienia współdziałania między językami dynamicznymi a .NET Framework oraz umożliwienia autorom kompilatora emitowania drzew wyrażeń zamiast języka MSIL (Microsoft Intermediate Language). Aby uzyskać więcej informacji na temat biblioteki DLR, zobacz Dynamic Language Runtime Overview (Omówienie środowiska uruchomieniowego języka dynamicznego).
Możesz mieć kompilator języka C# lub Visual Basic utworzyć drzewo wyrażeń na podstawie anonimowego wyrażenia lambda lub ręcznie utworzyć drzewa wyrażeń przy użyciu System.Linq.Expressions przestrzeni nazw.
Tworzenie drzew wyrażeń na podstawie wyrażeń lambda
Gdy wyrażenie lambda jest przypisywane do zmiennej typu Expression<TDelegate>, kompilator emituje kod w celu utworzenia drzewa wyrażeń reprezentującego wyrażenie lambda.
Kompilator Visual Basic może generować drzewa wyrażeń tylko z wyrażeń lambda (lub lambdy jednowierszowe). Nie może przeanalizować instrukcji lambdas (lub lambdy wielowierszowe). Aby uzyskać więcej informacji na temat wyrażeń lambda w Visual Basic, zobacz Wyrażenia lambda.
W poniższych przykładach kodu pokazano, jak kompilator Visual Basic utworzyć drzewo wyrażeń reprezentujące wyrażenie Function(num) num < 5
lambda .
Dim lambda As Expression(Of Func(Of Integer, Boolean)) =
Function(num) num < 5
Tworzenie drzew wyrażeń przy użyciu interfejsu API
Aby utworzyć drzewa wyrażeń przy użyciu interfejsu API, użyj Expression klasy . Ta klasa zawiera statyczne metody fabryki, które tworzą węzły drzewa wyrażeń określonych typów, ParameterExpressionna przykład , który reprezentuje zmienną lub parametr lub MethodCallExpression, który reprezentuje wywołanie metody. ParameterExpression, MethodCallExpressioni inne typy specyficzne dla wyrażeń są również zdefiniowane w System.Linq.Expressions przestrzeni nazw. Te typy pochodzą z typu Expressionabstrakcyjnego .
W poniższym przykładzie kodu pokazano, jak utworzyć drzewo wyrażeń reprezentujące wyrażenie Function(num) num < 5
lambda przy użyciu interfejsu API.
' 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})
W .NET Framework 4 lub nowszym interfejs API drzew wyrażeń obsługuje również przypisania i wyrażenia przepływu sterowania, takie jak pętle, bloki warunkowe i try-catch
bloki. Za pomocą interfejsu API można tworzyć drzewa wyrażeń, które są bardziej złożone niż te, które można tworzyć na podstawie wyrażeń lambda przez kompilator Visual Basic. W poniższym przykładzie pokazano, jak utworzyć drzewo wyrażeń, które oblicza współczynnik liczby.
' 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.
Aby uzyskać więcej informacji, zobacz Generowanie metod dynamicznych za pomocą drzew wyrażeń w Visual Studio 2010, który dotyczy również nowszych wersji Visual Studio.
Analizowanie drzew wyrażeń
W poniższym przykładzie kodu pokazano, w jaki sposób drzewo wyrażeń reprezentujące wyrażenie Function(num) num < 5
lambda może zostać rozłożone na jego części.
' 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
Niezmienność drzew wyrażeń
Drzewa wyrażeń powinny być niezmienne. Oznacza to, że jeśli chcesz zmodyfikować drzewo wyrażeń, musisz utworzyć nowe drzewo wyrażeń przez skopiowanie istniejącego i zastąpienie węzłów w nim. Możesz użyć odwiedzających drzewo wyrażeń, aby przejść przez istniejące drzewo wyrażeń. Aby uzyskać więcej informacji, zobacz Porady: modyfikowanie drzew wyrażeń (Visual Basic).
Kompilowanie drzew wyrażeń
Typ Expression<TDelegate> udostępnia metodę Compile , która kompiluje kod reprezentowany przez drzewo wyrażeń do delegata wykonywalnego.
W poniższym przykładzie kodu pokazano, jak skompilować drzewo wyrażeń i uruchomić wynikowy kod.
' 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.
Aby uzyskać więcej informacji, zobacz Instrukcje: wykonywanie drzew wyrażeń (Visual Basic).