¿Qué hace Expression.Reduce ()?

.net c# expression-trees lambda

Pregunta

He estado trabajando con árboles de expresiones durante unos días y tengo curiosidad por saber qué hace Expression.Reduce (). La documentación msdn no es muy útil ya que solo indica que "reduce" la expresión. Por si acaso, probé un ejemplo (ver más abajo) para verificar si este método incluía una reducción matemática, pero este no parece ser el caso.

¿Alguien sabe qué hace este método y es posible proporcionar un ejemplo rápido que lo muestre en acción? ¿Algún buen recurso por ahí?

static void Main(string[] args)
{
    Expression<Func<double, double>> func = x => (x + x + x) + Math.Exp(x + x + x);
    Console.WriteLine(func);
    Expression r_func = func.Reduce();
    Console.WriteLine(r_func); // This prints out the same as Console.WriteLine(func)
}

Respuesta aceptada

El documento que debe ver es "expr-tree-spec.doc" aquí: http://dlr.codeplex.com/wikipage?title=Docs%20and%20specs&referringTitle=Documentation

Esta es la especificación para los árboles de expresión. Lea las secciones "2.2 Nodos reducibles" y "4.3.5 Método de reducción".

Básicamente, este método está destinado a personas que implementan o portan sus idiomas dinámicos a .NET. Para que puedan crear sus propios nodos que puedan "reducirse" a nodos de árbol de expresión estándar y puedan compilarse. Hay algunos nodos "reducibles" en la API de los árboles de expresión, pero no sé si puede obtener algún ejemplo práctico (ya que todos los nodos de expresión estándar se compilan de todos modos, ya que el usuario final probablemente no le importa si están "reducidos". "detrás de las escenas o no).

Sí, la documentación de MSDN es muy básica en esta área, porque la fuente principal de información y documentos para los implementadores de idiomas es http://dlr.codeplex.com/


Respuesta popular

Con un poco de desmontaje, encontré que Expression.CanReduce siempre reutrns false y Expression.Reduce () siempre devuelve this . Sin embargo, hay algunos tipos que anulan ambos. LambdaExpression hereda las implementaciones predeterminadas, lo que explica por qué las expresiones que se han intentado hasta ahora no funcionan.

Uno de los tipos que reemplaza a Reduce () es MemberInitExpression, que me llevó al siguiente experimento exitoso:

class ReduceFinder : ExpressionVisitor {
    public override Expression Visit(Expression node) {
        if (node != null && node.CanReduce) {
            var reduced = node.Reduce();
            Console.WriteLine("Found expression to reduce!");
            Console.WriteLine("Before: {0}: {1}", node.GetType().Name, node);
            Console.WriteLine("After: {0}: {1}", reduced.GetType().Name, reduced);
        }
        return base.Visit(node);
    }
}

class Foo {
    public int x;
    public int y;
}

static class Program {
    static void Main() {
        Expression<Func<int, Foo>> expr = z => new Foo { x = (z + 1), y = (z + 1) };
        new ReduceFinder().Visit(expr);
    }
}

Salida:

Found expression to reduce!  
Before: MemberInitExpression: new Foo() {x = (z + 1), y = (z + 1)}  
After: ScopeN: { ... }  


Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow