如何:修改表达式目录树

更新:2007 年 11 月

本主题演示如何修改表达式目录树。表达式目录树是不可变的,这意味着不能直接修改表达式目录树。若要更改表达式目录树,必须创建现有表达式目录树的一个副本,并在创建副本的过程中执行所需更改。您可以使用表达式目录树访问器遍历现有表达式目录树,并复制它访问的每个节点。

修改表达式目录树

  1. 在 Visual Studio 中创建一个新的“控制台应用程序”项目。

  2. 添加对 System.Core.dll 的引用(如果尚未引用它的话)。

  3. 将 ExpressionVisitor 类添加到项目中。

    这些代码可在如何:实现表达式目录树访问器中获得。

    将 using 指令(或 Visual Basic 中的 Imports 语句)添加到以下命名空间的文件中:System.Collections.Generic、System.Collections.ObjectModel 和 System.Linq.Expressions。

  4. 将 AndAlsoModifier 类添加到项目中。

    该类继承 ExpressionVisitor 类,并且专用于修改表示条件 AND 运算的表达式。它将这些运算从条件 AND 更改为条件 OR。为此,该类将重写基类型的 VisitBinary 方法,这是因为条件 AND 表达式表示为二元表达式。在 VisitBinary 方法中,如果传递到该方法的表达式表示条件 AND 运算,代码将构造一个包含条件 OR 运算符(而不是条件 AND 运算符)的新表达式。如果传递到 VisitBinary 的表达式不表示条件 AND 运算,则该方法交由基类实现来处理。基类方法构造类似于传入的表达式目录树的节点,但这些节点将其子目录树替换为访问器递归生成的表达式目录树。

    Public Class AndAlsoModifier
        Inherits ExpressionVisitor
    
        Public Function Modify(ByVal expr As Expression) As Expression
            Return Visit(expr)
        End Function
    
        Protected Overrides Function VisitBinary(ByVal b As BinaryExpression) As Expression
            If b.NodeType = ExpressionType.AndAlso Then
                Dim left = Me.Visit(b.Left)
                Dim right = Me.Visit(b.Right)
    
                ' Make this binary expression an OrElse operation instead 
                ' of an AndAlso operation.
                Return Expression.MakeBinary(ExpressionType.OrElse, left, right, _
                                             b.IsLiftedToNull, b.Method)
            End If
    
            Return MyBase.VisitBinary(b)
        End Function
    End Class
    
    public class AndAlsoModifier : ExpressionVisitor
    {
        public Expression Modify(Expression expression)
        {
            return Visit(expression);
        }
    
        protected override Expression VisitBinary(BinaryExpression b)
        {
            if (b.NodeType == ExpressionType.AndAlso)
            {
                Expression left = this.Visit(b.Left);
                Expression right = this.Visit(b.Right);
    
                // Make this binary expression an OrElse operation instead of an AndAlso operation.
                return Expression.MakeBinary(ExpressionType.OrElse, left, right, b.IsLiftedToNull, b.Method);
            }
    
            return base.VisitBinary(b);
        }
    }
    

    将 using 指令(或 Visual Basic 中的 Imports 语句)添加到 System.Linq.Expressions 命名空间的文件中。

  5. 将代码添加到 Program.cs(在 Visual Basic 为 Module1.vb)内的 Main 方法中,以便创建表达式目录树,并将其传递到要修改它的方法中。

    下面的代码创建一个包含条件 AND 运算的表达式。然后创建 AndAlsoModifier 类的实例,并将表达式传递到该类的 Modify 方法。将输出原始表达式目录树和修改过后的表达式目录树,以显示更改。

    Dim expr As Expression(Of Func(Of String, Boolean)) = _
        Function(name) name.Length > 10 AndAlso name.StartsWith("G")
    
    Console.WriteLine(expr)
    
    Dim modifier As New AndAlsoModifier()
    Dim modifiedExpr = modifier.Modify(CType(expr, Expression))
    
    Console.WriteLine(modifiedExpr)
    
    ' This code produces the following output:
    ' name => ((name.Length > 10) && name.StartsWith("G"))
    ' name => ((name.Length > 10) || name.StartsWith("G"))
    
    
    Expression<Func<string, bool>> expr = name => name.Length > 10 && name.StartsWith("G");
    Console.WriteLine(expr);
    
    AndAlsoModifier treeModifier = new AndAlsoModifier();
    Expression modifiedExpr = treeModifier.Modify((Expression) expr);
    
    Console.WriteLine(modifiedExpr);
    
    /*  This code produces the following output:
    
        name => ((name.Length > 10) && name.StartsWith("G"))
        name => ((name.Length > 10) || name.StartsWith("G"))
    */
    
    

    将 using 指令(或 Visual Basic 中的 Imports 语句)添加到 System.Linq.Expressions 命名空间的文件中。

  6. 编译并运行应用程序。

请参见

任务

如何:执行表达式目录树

演练:创建 IQueryable LINQ 提供程序

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

概念

表达式目录树