表达式树以树形数据结构表示代码,其中每个节点都是一种表达式,好比方法调用和 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.