Comment fonctionne PredicateBuilder

.net c# expression-trees linq predicatebuilder

Question

C # in a Nutshell a une classe gratuite appelée PredicateBuilder qui construit pièce par pièce les prédicats LINQ disponible ici . Voici un extrait de la méthode qui ajoute une nouvelle expression au prédicat. Quelqu'un pourrait-il l'expliquer? (J'ai vu cette question , je ne veux pas de réponse générale comme celle-ci. Je cherche une explication spécifique sur la manière dont Expression.Invoke et Expression.Lambda construisent la nouvelle expression).

public static Expression<Func<T, bool>> And<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.AndAlso (expr1.Body, invokedExpr), expr1.Parameters);
}

Réponse acceptée

Disons que vous avez:

Expression<Func<Person, bool>> isAdult = p1 => p1.Age >= 18;

// I've given the parameter a different name to allow you to differentiate.
Expression<Func<Person, bool>> isMale = p2 => p2.Gender == "Male";

Et puis combinez-les avec PredicateBuilder

var isAdultMale = isAdult.And(isMale);

Ce que PredicateBuilder produit est une expression qui ressemble à ceci:

// Invoke has no direct equivalent in C# lambda expressions.
p1 => p1.Age >= 18 && Invoke(p2 => p2.Gender == "Male", p1)

Comme vous pouvez le voir:

  1. Le lambda résultant réutilise les paramètres de la première expression.
  2. A un corps qui invoque la deuxième expression en transmettant les paramètres de la première expression en remplacement des paramètres de la deuxième expression. L' InvocationExpression obtenue est un peu comme l'équivalent d'expression d'un appel de méthode (appel d'une routine en transmettant des arguments pour les paramètres).
  3. And s le corps de la première expression et cette InvocationExpression ensemble pour produire le corps du lambda résultant.

L'idée est que le fournisseur LINQ devrait être en mesure de comprendre la sémantique de cette opération et de prendre des mesures judicieuses (par exemple, générer du code SQL comme WHERE age >= 18 AND gender = 'Male' ).

Cependant, les fournisseurs ont souvent des problèmes avec les expressions InvocationExpression , en raison des complications évidentes du traitement d'un "appel d'expression imbriqué dans une expression".

Pour contourner ce problème, LINQKit fournit également l' Expand aide. Ceci "insère" intelligemment l'appel d'appel de manière intelligente en remplaçant l'appel par le corps de l'expression imbriquée, en substituant les utilisations des paramètres de l'expression imbriquée de manière appropriée (dans ce cas, en remplaçant p2 par p1 ). Cela devrait produire quelque chose comme:

p1 => p1.Age >= 18 && p1.Gender == "Male"

Notez que vous auriez combiné manuellement ces prédicats si vous l’aviez fait vous-même dans un lambda. Mais avec LINQKit, vous pouvez obtenir ces prédicats auprès de sources indépendantes et les combiner facilement:

  1. Sans écrire le code d'expression "à la main".
  2. Facultativement, de manière transparente pour les consommateurs du lambda résultant.



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