web-dev-qa-db-fra.com

Comment fonctionne PredicateBuilder

C # en bref a une classe gratuite appelée PredicateBuilder qui construit les prédicats LINQ disponibles pièce par pièce 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 façon 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);
}
30

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 appelle la deuxième expression en passant les paramètres de la première expression en remplacement des paramètres de la seconde expression. Le résultat InvocationExpression est un peu comme l'équivalent d'expression d'un appel de méthode (appel d'une routine en passant des arguments pour les paramètres).
  3. Ands le corps de la première expression et ce InvocationExpression ensemble pour produire le corps du lambda résultant.

L'idée est que le fournisseur LINQ devrait être capable de comprendre la sémantique de cette opération et de prendre une ligne de conduite sensée (par exemple, générer du SQL comme WHERE age >= 18 AND gender = 'Male').

Souvent, cependant, les fournisseurs ont des problèmes avec InvocationExpressions, 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'aide Expand. Cela `` inline '' intelligemment l'appel d'invocation en remplaçant l'appel par le corps de l'expression imbriquée, en remplaçant les utilisations des paramètres de l'expression imbriquée de manière appropriée (dans ce cas, remplaçant p2 avec p1). Cela devrait produire quelque chose comme:

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

Notez que c'est ainsi 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 à partir de sources indépendantes et les combiner facilement:

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