Comment créer une expression <Func<dynamic, dynamic> &gt; - Ou est-ce un bug?

.net-4.0 c# dynamic expression-trees lambda

Question

Depuis quelques jours que je travaille avec des arbres d’expression, je suis tombé sur quelque chose que je trouve difficile à comprendre; J'espère que quelqu'un pourra ainsi faire la lumière ici.

Si vous codez Expression<Func<dynamic, dynamic>> expr1 = x => 2 * x; le compilateur va se plaindre et vous n'irez nulle part. Cependant, il semble que si vous créez une telle expression via une méthode, le compilateur semble en être heureux et l'application résultante fonctionne. Cela n’a aucun sens, alors je me demande ce qui se passe derrière les rideaux.

Je suppose que, sous le capot, l'expression renvoyée par ConvertExpression est peut-être de type Expression<Func<object, object>> , qui est un type valide, mais cela me ConvertExpression perplexe de ne pas pouvoir utiliser Expression<Func<dynamic, dynamic>> tapez une déclaration et pourtant je peux l'utiliser comme type de retour d'une méthode. Voir un exemple ci-dessous.

Merci beaucoup!

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

Réponse acceptée

Je suppose que, sous le capot, l'expression renvoyée par ConvertExpression est peut-être de type Expression<Func<object, object>> , qui est un type valide

Correct.

Je ne peux pas utiliser le type Expression<Func<dynamic, dynamic>> dans une déclaration et pourtant je peux l'utiliser comme type de retour d'une méthode.

Cette partie de la déclaration est incorrecte. Comme vous le constatez dans votre exemple, il est parfaitement légal d'utiliser ce type dans la déclaration d'une variable locale.

Le bit qui n’est pas légal est l’exécution d’une opération dynamique à l’intérieur d’un lambda en cours de conversion en type d’arbre d’expression. Le type d'arbre d'expression spécifique n'est pas pertinent; ce qui compte, c’est que l’opération soit dynamique.


Réponse populaire

L'erreur du compilateur que j'ai rencontrée lorsque j'ai essayé votre code était "erreur CS1963: un arbre d'expression ne peut pas contenir d'opération dynamique". J'ai changé la ligne du problème en Expression<Func<dynamic, dynamic>> expr1 = x => x; (retirant le "fonctionnement" du lambda) et ça a fonctionné! Ainsi, vous êtes autorisé à avoir des expressions dynamiques, mais vous ne pouvez en réalité effectuer aucune "opération" dessus. Pas très utile, je sais. Dans mes tests, même .ToString() compte comme une opération.




Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi