如何:修改表达式树(C# 和 Visual Basic)
本主题演示如何修改表达式树。表达式树是不可变的,这意味着不能直接修改表达式树。若要更改表达式树,必须创建现有表达式树的一个副本,并在创建副本的过程中执行所需更改。您可以使用 ExpressionVisitor 类遍历现有表达式树,并复制它访问的每个节点。
说明 |
---|
可以在 CodePlex 网站上找到 ExpressionVisitor 类的源代码。 |
修改表达式树
在 Visual Studio 中创建一个新的**“控制台应用程序”**项目。
将 AndAlsoModifier 类添加到项目中。
该类继承 ExpressionVisitor 类,并且专用于修改表示条件 AND 运算的表达式。它将这些运算从条件 AND 更改为条件 OR。为此,该类将重写基类型的 VisitBinary 方法,这是因为条件 AND 表达式表示为二元表达式。在 VisitBinary 方法中,如果传递到该方法的表达式表示条件 AND 运算,代码将构造一个包含条件 OR 运算符(而不是条件 AND 运算符)的新表达式。如果传递到 VisitBinary 的表达式不表示条件 AND 运算,则该方法交由基类实现来处理。基类方法构造类似于传入的表达式树的节点,但这些节点将其子目录树替换为访问器递归生成的表达式树。
将 using 指令(或 Visual Basic 中的 Imports 语句)添加到 System.Linq.Expressions 命名空间的文件中。
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); } }
将代码添加到 Program.cs(在 Visual Basic 为 Module1.vb)内的 Main 方法中,以便创建表达式树,并将其传递到要修改它的方法中。
下面的代码创建一个包含条件 AND 运算的表达式。然后创建 AndAlsoModifier 类的实例,并将表达式传递到该类的 Modify 方法。将输出原始表达式树和修改过后的表达式树,以显示更改。
将 using 指令(或 Visual Basic 中的 Imports 语句)添加到 System.Linq.Expressions 命名空间的文件中。
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")) */
编译并运行应用程序。