運算式樹狀架構
更新:2007 年 11 月
運算式樹狀架構會以資料形式表示語言層級的程式碼。這些資料會儲存成樹狀結構形狀的結構。運算式樹狀架構內的每一個節點都代表一個運算式,例如,方法呼叫或如 x < y 一類的二進位運算。
下圖顯示運算式的範例,以及該運算式的運算式樹狀架構表示方式。運算式的不同部分會以色彩標示,以符合運算式樹狀架構中的對應運算式樹狀架構節點。圖中也顯示了不同型別的運算式樹狀架構節點。
下列程式碼範例將示範如何將表示 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(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 命名空間 (Namespace) 提供了可手動建置 (Build) 運算式樹狀架構的 API。Expression 類別包含可建立特定型別之運算式樹狀架構節點的靜態 Factory 方法,例如 ParameterExpression 即代表具名參數運算式,而 MethodCallExpression 則代表方法呼叫。ParameterExpression、MethodCallExpression 和其他運算式專屬的運算式樹狀架構型別也會定義於 System.Linq.Expressions 命名空間中。這些型別是衍生自抽象型別 Expression。
編譯器 (Compiler) 也可以為您建置運算式樹狀架構。由編譯器產生的運算式樹狀架構一定會以型別 Expression<TDelegate> 的節點做為其根節點,也就是說,它的根節點可代表 Lambda 運算式。
下列程式碼範例將示範兩種方法,這些方法會建立可表示 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})
' 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;
運算式樹狀架構的不變性
運算式樹狀架構是不可變的。這表示如果要修改運算式樹狀架構,您就必須藉由複製現有的運算式樹狀架構,然後對其進行修改,以建構一個新的運算式樹狀架構。您可以使用運算式樹狀架構訪問項來周遊現有的運算式樹狀架構。如需詳細資訊,請參閱 HOW TO:實作運算式樹狀架構訪問項和 HOW TO:修改運算式樹狀架構。
Lambda 運算式
將 Lambda 運算式指派給型別 Expression<TDelegate> 的變數時,編譯器就會發出表示 Lambda 運算式的運算式樹狀架構。例如,有些定義在 Queryable 類別中的標準查詢運算子方法會具有型別 Expression<TDelegate> 的參數。呼叫這些方法時,您可以傳入 Lambda 運算式,此時編譯器將會產生運算式樹狀架構。
Expression<TDelegate> 型別提供了 Compile 方法,此方法會將運算式樹狀架構所表示的程式碼編譯為可執行的委派 (Delegate)。這個可執行程式碼相當於原本就將 Lambda 運算式指派給委派型別所產生的可執行程式碼。
注意事項: |
---|
只有那些代表函式 (即 Expression<TDelegate>) 及其父型別 LambdaExpression 的運算式樹狀架構可以編譯為可執行程式碼。若要執行其他型別的運算式樹狀架構,您必須先將這些運算式樹狀架構包裝在 LambdaExpression 節點中。您可以藉由呼叫 Lambda 方法,並將運算式樹狀架構當做引數傳遞,以取得此類的 LambdaExpression。 |