表达式目录树

更新: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 命名空间提供用于手动生成表达式目录树的 API。Expression 类包含创建特定类型的表达式目录树节点的静态工厂方法,例如,ParameterExpression(表示一个已命名的参数表达式)或 MethodCallExpression(表示一个方法调用)。System.Linq.Expressions 命名空间中还定义了 ParameterExpressionMethodCallExpression 和其他特定于表达式的表达式目录树类型。这些类型派生自抽象类型 Expression

编译器也可以为您生成表达式目录树。编译器生成的表达式目录树的根始终在类型 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;

表达式目录树的不可变性

表达式目录树是不可变的。这意味着,如果需要修改某个表达式目录树,则必须通过复制现有的表达式目录树并对其进行修改来构造一个新的表达式目录树。您可以使用表达式目录树访问器来遍历现有表达式目录树。有关更多信息,请参见如何:实现表达式目录树访问器如何:修改表达式目录树

lambda 表达式

在将 lambda 表达式分配给 Expression<TDelegate> 类型的变量时,编译器将发出一个表示 lambda 表达式的表达式目录树。例如,在 Queryable 类中定义的某些标准查询运算符方法包含 Expression<TDelegate> 类型的参数。当您调用这些方法时,可以传入 lambda 表达式,然后编译器会生成表达式目录树。

Expression<TDelegate> 类型提供 Compile 方法,该方法将表达式目录树表示的代码编译成一个可执行委托。此可执行代码等同于最初已将 lambda 表达式分配给委托类型而生成的可执行代码。

说明:

只有表示 Expression<TDelegate> 函数及其父类型 LambdaExpression 的那些表达式目录树才可以编译成可执行代码。若要执行其他类型的表达式目录树,必须先将它们包装在 LambdaExpression 节点中。可以通过调用 Lambda 方法并将表达式目录树作为参数传递来获得这样一个 LambdaExpression

请参见

任务

如何:执行表达式目录树

如何:修改表达式目录树

如何:实现表达式目录树访问器

概念

LINQ 中的表达式树

lambda 表达式

参考

Lambda 表达式(C# 编程指南)

System.Linq.Expressions