運算式樹狀架構 (C# 和 Visual Basic)
運算式樹狀架構代表樹狀資料結構中的程式碼,其中每一個節點都代表一個運算式,例如,方法呼叫或如 x < y 一類的二進位運算。
您可以編譯並執行運算式樹狀架構所代表的程式碼。 如此可提供動態修改可執行程式碼、在各種資料庫中執行 LINQ 查詢,以及建立動態查詢。 如需 LINQ 中運算式樹狀架構的詳細資訊,請參閱 HOW TO:使用運算式樹狀結構建置動態查詢 (C# 和 Visual Basic)和逐步解說:建立 IQueryable LINQ 提供者。
運算式樹狀架構也可用於 Dynamic Language Runtime (DLR),提供動態語言和 .NET Framework 之間的互通性,並可讓編譯器寫入器發出運算式樹狀架構,而非 Microsoft Intermediate Language (MSIL)。 如需 DLR 的詳細資訊,請參閱 Dynamic Language Runtime 概觀。
C# 或 Visual Basic 編譯器可以根據匿名 Lambda 運算式為您建立運算式樹狀架構,或者您也可以使用 System.Linq.Expressions 命名空間手動建立運算式樹狀架構。
從 Lambda 運算式建立運算式樹狀架構
將 Lambda 運算式指派給型別 Expression<TDelegate> 的變數時,編譯器就會發出程式碼,建置表示 Lambda 運算式的運算式樹狀架構。
C# 和 Visual Basic 編譯器只能從運算式 Lambda (或單行 Lambda) 產生運算式樹狀架構, 無法剖析陳述式 Lambda (或多行 Lambda)。 如需 C# 中 Lambda 運算式的詳細資訊,請參閱 Lambda 運算式 (C# 程式設計手冊);至於 Visual Basic,請參閱 Lambda 運算式 (Visual Basic)。
下列程式碼範例將示範 C# 和 Visual Basic 編譯器如何建立可表示 Lambda 運算式 num => num < 5 (C#) 或 Function(num) num < 5 (Visual Basic) 的運算式樹狀架構。
Dim lambda As Expression(Of Func(Of Integer, Boolean)) =
Function(num) num < 5
Expression<Func<int, bool>> lambda = num => num < 5;
使用 API 建立運算式樹狀架構
若要使用 API 建立運算式樹狀架構,請使用 Expression 類別。 此類別包含可建立特定型別之運算式樹狀架構節點的靜態 Factory 方法,例如 ParameterExpression 代表變數或參數,而 MethodCallExpression 則代表方法呼叫。 ParameterExpression、MethodCallExpression 和其他運算式專屬型別也會定義於 System.Linq.Expressions 命名空間中。 這些型別是衍生自抽象型別 Expression。
下列程式碼範例將示範如何使用 API 建立可表示 Lambda 運算式 num => num < 5 (C#) 或 Function(num) num < 5 (Visual Basic) 的運算式樹狀架構。
' 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})
// 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 });
在 .NET Framework 4 中,運算式樹狀架構 API 也支援指派和控制流程運算式,例如迴圈、條件區塊以及 try-catch 區塊。 使用 API 所建立的運算式樹狀架構,可以比 C# 或 Visual Basic 編譯器根據 Lambda 運算式所建立的運算式樹狀架構更為複雜。 下列範例將示範如何建立計算數字之階乘的運算式樹狀架構。
' 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.
// Creating a parameter expression.
ParameterExpression value = Expression.Parameter(typeof(int), "value");
// Creating an expression to hold a local variable.
ParameterExpression result = Expression.Parameter(typeof(int), "result");
// Creating a label to jump to from a loop.
LabelTarget label = Expression.Label(typeof(int));
// Creating a method body.
BlockExpression block = Expression.Block(
// Adding a local variable.
new[] { result },
// Assigning a constant to a local variable: result = 1
Expression.Assign(result, Expression.Constant(1)),
// Adding a loop.
Expression.Loop(
// Adding a conditional block into the loop.
Expression.IfThenElse(
// Condition: value > 1
Expression.GreaterThan(value, Expression.Constant(1)),
// If true: result *= value --
Expression.MultiplyAssign(result,
Expression.PostDecrementAssign(value)),
// If false, exit the loop and go to the label.
Expression.Break(label, result)
),
// Label to jump to.
label
)
);
// Compile and execute an expression tree.
int factorial = Expression.Lambda<Func<int, int>>(block, value).Compile()(5);
Console.WriteLine(factorial);
// Prints 120.
如需詳細資訊,請參閱在 Visual Studio 2010 中使用運算式樹狀架構產生動態方法 (英文)。
剖析運算式樹狀架構
下列程式碼範例將示範如何將表示 Lambda 運算式 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(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
// 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
運算式樹狀架構的不變性
運算式樹狀架構應該是不可變的。 這表示如果要修改運算式樹狀架構,您就必須藉由複製現有的運算式樹狀架構並取代其中節點,以建構一個新的運算式樹狀架構。 您可以使用運算式樹狀架構訪問項來周遊現有的運算式樹狀架構。 如需詳細資訊,請參閱 HOW TO:修改運算式樹狀架構 (C# 和 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.
// Creating an expression tree.
Expression<Func<int, bool>> expr = num => num < 5;
// Compiling the expression tree into a delegate.
Func<int, bool> result = 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.
如需詳細資訊,請參閱 HOW TO:執行運算式樹狀結構 (C# 和 Visual Basic)。
請參閱
工作
HOW TO:執行運算式樹狀結構 (C# 和 Visual Basic)
HOW TO:修改運算式樹狀架構 (C# 和 Visual Basic)