Cómo crear una expresión > - ¿O es un error?

.net-4.0 c# dynamic expression-trees lambda

Pregunta

Durante mi trabajo con árboles de expresión durante unos días, encontré algo que me resulta difícil de entender; Espero que alguien pueda así arrojar algo de luz aquí.

Si codifica Expression<Func<dynamic, dynamic>> expr1 = x => 2 * x; El compilador se quejará y no llegarás a ninguna parte. Sin embargo, parece que si creas una expresión de este tipo a través de un método, entonces el compilador parece estar contento con eso y la aplicación resultante funciona. Esto no tiene sentido, así que me pregunto qué sucede detrás de las cortinas.

Supongo que, bajo el capó, la expresión devuelta por ConvertExpression es quizás de tipo Expression<Func<object, object>> , que es un tipo válido, pero me desconcierta que no pueda usar Expression<Func<dynamic, dynamic>> escriba una declaración y, sin embargo, puedo usarla como el tipo de retorno de un método. Vea un ejemplo a continuación.

¡Muchas gracias!

public class ExpressionExample
{
    public void Main()
    {
        // Doesn't compile:
        //Expression<Func<dynamic, dynamic>> expr1 = x => 2 * x;

        // Compiles and works - OK
        Expression<Func<double, double>> expr2 = x => 2 * x;
        Func<double, double> func2 = (Func<double, double>)expr2.Compile();
        Console.WriteLine(func2(5.0).ToString()); // Outputs 10

        // Compiles and works - ??? This is the confusing block...
        Expression<Func<dynamic, dynamic>> expr3 = ConvertExpression(expr2);
        Func<dynamic, dynamic> func3 = (Func<dynamic, dynamic>)expr3.Compile();
        Console.WriteLine(func3(5.0).ToString()); // Outputs 10

        // Side note: compiles and works:
        Expression<Func<object, object>> expr4 = x => double.Parse(2.ToString()) * double.Parse(x.ToString());
        Func<object, object> func4 = (Func<object, object>)expr4.Compile();
        Console.WriteLine(func4(5.0).ToString()); // Outputs 10
    }

    private Expression<Func<dynamic, dynamic>> ConvertExpression<TInput, TOutput>(Expression<Func<TInput, TOutput>> expression)
    {
        Expression<Func<object, TInput>> convertToInput = value => (TInput)value;
        // The following doesn't compile: var input = Expression.Parameter(typeof(dynamic), "input");

        var input = Expression.Parameter(typeof(object), "input");        

        Expression<Func<TOutput, dynamic>> convertToOutput = value => (dynamic)value;

        var body = Expression.Invoke(convertToOutput, Expression.Invoke(expression, Expression.Invoke(convertToInput, input)));
        var lambda = Expression.Lambda<Func<dynamic, dynamic>>(body, input);

        return lambda;
    }
}

Respuesta aceptada

Supongo que, bajo el capó, la expresión devuelta por ConvertExpression es quizás de tipo Expression<Func<object, object>> , que es un tipo válido

Correcto.

No puedo usar el tipo de Expression<Func<dynamic, dynamic>> en una declaración y, sin embargo, puedo usarlo como el tipo de retorno de un método.

Esta parte de la declaración es incorrecta. Como señala en su ejemplo, es perfectamente legal usar ese tipo en la declaración de una variable local.

El bit que no es legal es la ejecución de una operación dinámica dentro de un lambda que se está convirtiendo en un tipo de árbol de expresión. El tipo de árbol de expresión específica es irrelevante; Lo que importa es que la operación sea dinámica.


Respuesta popular

El error del compilador que obtuve cuando probé el código fue "error CS1963: es posible que un árbol de expresiones no contenga una operación dinámica". Cambié la línea del problema a Expression<Func<dynamic, dynamic>> expr1 = x => x; (quitando la "operación" de la lambda) y funcionó! Por lo tanto, se le permite tener dinámicas en las expresiones, pero en realidad no puede realizar ninguna "operación" en ellas. No muy útil, lo sé. En mis pruebas, incluso .ToString() cuenta como una operación.



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