Comprendre la méthode Expression.Invoke ()

c# expression-trees

Question

J'ai compris les méthodes d'extension PredicateBuilder écrites par Joseph Albahari et j'ai vu cette Expression.Invoke . Invoquer et honnêtement, je ne pouvais pas en comprendre la raison dans la méthode suivante:

public static Expression<Func<T, bool>> Or<T> (this Expression<Func<T, bool>> 
       expr1, Expression<Func<T, bool>> expr2)
{
  var invokedExpr = Expression.Invoke (expr2, 
      expr1.Parameters.Cast<Expression> ());

  return Expression.Lambda<Func<T, bool>> 
       (Expression.OrElse (expr1.Body, invokedExpr), expr1.Parameters);
}

Même s'il l'expliqua un peu:

Le travail intéressant se déroule dans les méthodes And and Or. Nous commençons par appeler la deuxième expression avec les paramètres de la première expression. Une expression Invoke appelle une autre expression lambda en utilisant les expressions données comme arguments. Nous pouvons créer l'expression conditionnelle à partir du corps de la première expression et de la version invoquée de la seconde. La dernière étape consiste à envelopper ceci dans une nouvelle expression lambda.

MSDN me dit que:

Crée une InvocationExpression qui applique une expression déléguée ou lambda à une liste d'expressions d'arguments.

et cela me semble un peu logique. Donc, fondamentalement, je n'ai pas besoin de passer d'argument si j'utilise l'expression comme ça.

Mais pour une raison quelconque, je ne pouvais pas tout comprendre. Peut-être que je suis fatigué ou quelque chose.

Des questions:

  1. Quand et dans quelle situation est-il utile d'utiliser InvocationExpression .
  2. Quelqu'un peut-il expliquer comment la méthode Or<T> (ou AndElse<T> ) fonctionne un peu mieux?

Mettre à jour:

Je pensais à InvocationExpression quand je rentrais du travail à la maison et cela me faisait penser à ceci:

Lorsque nous appelons une méthode, nous disons simplement CallMe(phoneNumber, time); et cela s'appelle invocation de méthode. Ensuite, InvocationExpression doit être une expression qui exprime CallMe(phoneNumber, time); . Il est similaire à LambdaExpression qui exprime un lambda tel que t => t + 2 . Il s’agit donc d’une invocation de méthode qui s’applique à des arguments (et non à des paramètres). Donc, en tant qu’invocation, il n’est plus prévu d’avoir besoin de paramètres, mais peut-être de renvoyer quelque chose puisque les arguments sont déjà appliqués à ses paramètres.

Pour plus d'informations sur le code dont je parle, visitez le site http://www.albahari.com/nutshell/predicatebuilder.aspx

Réponse acceptée

Imaginez que vous ne travailliez pas avec des expressions, mais avec des délégués. Ensuite, vous pouvez écrire Or comme ceci:

public static Func<T, bool> Or<T>(this Func<T, bool> expr1, Func<T, bool> expr2)
{
    return x => expr1(x) || expr2(x);
}

Vous créez un nouveau délégué qui appelle les deux délégués, combinés avec || . Lorsque vous réécrivez ceci pour utiliser des expressions, l'appel d'un délégué se transforme en Expression.Invoke() :

public static Expression<Func<T, bool>> Or<T>(
    this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
    var parameter = Expression.Parameter(typeof(T), "x");
    var invokedExpr1 = Expression.Invoke(expr1, parameter);
    var invokedExpr2 = Expression.Invoke(expr2, parameter);

    return Expression.Lambda<Func<T, bool>>(
        Expression.OrElse(invokedExpr1, invokedExpr2), parameter);
}

La raison pour laquelle le libellé Or n'est pas écrit comme ceci est (très probablement) une optimisation: vous n'avez pas à invoquer les deux expressions, vous pouvez réutiliser le corps et le paramètre de l'une d'entre elles. (Mais vous ne pouvez pas les réutiliser tous les deux, car ils ont des paramètres différents.)



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow