Cómo: Modificar árboles de expresiones

Actualización: noviembre 2007

En este tema se muestra cómo se modifica un árbol de expresión. Los árboles de expresiones son inmutables, lo que significa que no se pueden modificar directamente. Para cambiar un árbol de expresión, debe crear una copia de un árbol de expresión existente y, después de crear la copia, realizar las modificaciones necesarias. Puede utilizar un visitante de árbol de expresión para recorrer un árbol de expresión existente y copiar cada uno de los nodos que visite.

Para modificar un árbol de expresión

  1. En Visual Studio, cree un nuevo proyecto de Aplicación de consola.

  2. Agregue una referencia a System.Core.dll si ésta no existe aún.

  3. Agregue la clase ExpressionVisitor al proyecto.

    Este código está disponible en Cómo: Implementar un visitante de árbol de expresión.

    Agregue directivas using (o instrucciones Imports en Visual Basic) al archivo para los espacios de nombres siguientes: System.Collections.Generic, System.Collections.ObjectModel y System.Linq.Expressions.

  4. Agregue la clase AndAlsoModifier al proyecto.

    Esta clase hereda la clase ExpressionVisitor y está especializada en la modificación de expresiones que representan operaciones AND condicionales. Esta clase cambia estas operaciones de un operador AND condicional a un operador OR condicional. Para ello, la clase invalida el método VisitBinary del tipo base, ya que las expresiones AND condicionales se representan como expresiones binarias. En el método VisitBinary, si la expresión que se pasa representa una operación AND condicional, el código construye una nueva expresión que contiene el operador OR condicional en lugar del operador AND condicional. Si la expresión que se pasa a VisitBinary no representa una operación AND condicional, el método pasa a la implementación de la clase base. Los métodos de clase base construyen nodos que son como los árboles de expresiones que se pasan, pero los subárboles de los nodos se sustituyen por los árboles de expresiones que el visitante genera de forma recursiva.

    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);
        }
    }
    

    Agregue una directiva using (o una instrucción Imports en Visual Basic) al archivo para el espacio de nombres System.Linq.Expressions.

  5. Agregue código al método Main del archivo Program.cs (Module1.vb en Visual Basic) para crear un árbol de expresión y pasarlo al método que lo modificará.

    El código siguiente crea una expresión que contiene una operación AND condicional. A continuación, crea una instancia de la clase AndAlsoModifier y pasa la expresión al método Modify de esta clase. Tanto el árbol de expresión original como el árbol de expresión modificado se generan para mostrar los cambios.

    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"))
    */
    
    

    Agregue una directiva using (o una instrucción Imports en Visual Basic) al archivo para el espacio de nombres System.Linq.Expressions.

  6. Compile y ejecute la aplicación.

Vea también

Tareas

Cómo: Ejecutar árboles de expresiones

Tutorial: Crear un proveedor LINQ IQueryable

Cómo: Implementar un visitante de árbol de expresión

Conceptos

Árboles de expresiones