表達式樹以樹形數據結構表示代碼,其中每個節點都是一種表達式,好比方法調用和 x < y
這樣的二元運算等。數據庫
你能夠對錶達式樹中的代碼進行編輯和運算。 這樣可以動態修改可執行代碼、在不一樣數據庫中執行 LINQ 查詢以及建立動態查詢。 有關 LINQ 中表達式樹的詳細信息,請參閱 如何:使用表達式樹來生成動態查詢。express
表達式樹還能用於動態語言運行時 (DLR) 以提供動態語言和 .NET Framework 之間的互操做性,同時保證編譯器編寫員可以發射表達式樹而非 Microsoft 中間語言 (MSIL)。 有關 DLR 的詳細信息,請參閱 動態語言運行時概述。數據結構
你能夠基於匿名 lambda 表達式經過 C# 或者 Visual Basic 編譯器建立表達式樹,或者經過 System.Linq.Expressions 名稱空間手動建立。ide
若 lambda 表達式被分配給 Expression<TDelegate> 類型的變量,則編譯器能夠發射代碼以建立表示該 lambda 表達式的表達式樹。ui
C# 和 Visual Basic 編譯器只能從表達式 lambda (或單行 lambda)生成表達式樹。 它沒法解析語句 lambda (或多行 lambda)。 有關 C# 中 lambda 表達式的詳細信息,請參閱 Lambda 表達式;有關 Visual Basic 的詳細信息,請參閱 lambda 表達式。spa
下列代碼示例展現如何經過 C# 和 Visual Basic 編譯器建立表示 lambda 表達式 num => num < 5
(C#) 或 Function(num) num < 5
(Visual Basic) 的表達式樹。code
Expression<Func<int, bool>> lambda = num => num < 5;
經過 API 建立表達式樹須要使用 Expression 類。 類包含建立特定類型表達式樹節點的靜態工廠方法,好比表示參數變量的 ParameterExpression,或者是表示方法調用的 MethodCallExpression。 System.Linq.Expressions 名稱空間還解釋了 ParameterExpression、MethodCallExpression和另外一種具體表達式類型。 這些類型來源於抽象類型 Expression。rem
下列代碼示例展現如何經過 API 建立表示 lambda 表達式 num => num < 5
(C#)
或 Function(num) num < 5
(Visual Basic) 的表達式樹。
// 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
塊等。 相較於經過 C# 和 Visual Basic 編譯器根據 lambda 表達式建立表達式樹,你能利用 API 建立更加複雜的表達式樹。 下列示例展現如何建立計算數字階乘的表達式樹。
// 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.
下列代碼示例展現如何分解表示 lambda 表達式 num => num < 5
(C#) 或 Function(num) num < 5
(Visual Basic) 的表達式樹。
// 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
表達式樹應具備永久性。 這意味着若是你想修改某個表達式樹,則必須複製該表達式樹而後替換其中的節點來建立一個新的表達式樹。 你能夠使用表達式樹訪問者遍歷現有表達式樹。 有關詳細信息,請參閱如何:修改表達式樹。
Expression<TDelegate> 類型提供了 Compile 方法以將表達式樹表示的代碼編譯成可執行委託。
下列代碼示例展現如何編譯表達式樹並運行結果代碼。
// 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.