Wie funktioniert PredicateBuilder?

.net c# expression-trees linq predicatebuilder

Frage

C # in a Nutshell hat eine freie Klasse PredicateBuilder genannt , die LINQ Stück für Stück baut Prädikate verfügbar hier . Hier ist ein Auszug der Methode, die dem Prädikat einen neuen Ausdruck hinzufügt. Könnte es jemand erklären? (Ich habe diese Frage gesehen , ich möchte keine allgemeine Antwort wie dort. Ich suche nach einer spezifischen Erklärung, wie Expression.Invoke und Expression.Lambda den neuen Ausdruck aufbauen).

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

Akzeptierte Antwort

Sagen wir, du hast:

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

Und dann kombinieren Sie sie mit PredicateBuilder

var isAdultMale = isAdult.And(isMale);

Was PredicateBuilder erzeugt, ist ein Ausdruck, der folgendermaßen aussieht:

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

Wie du siehst:

  1. Das resultierende Lambda verwendet die Parameter des ersten Ausdrucks erneut.
  2. Hat einen Body, der den zweiten Ausdruck aufruft , indem er die Parameter des ersten Ausdrucks als Ersatz für die Parameter des zweiten Ausdrucks übergibt. Die resultierende InvocationExpression in gewisser Weise dem Ausdruck-Äquivalent eines Methodenaufrufs (Aufruf einer Routine durch Übergabe von Argumenten für Parameter).
  3. And s der Körper des ersten Ausdrucks und diese InvocationExpression zusammen, um den Körper des resultierenden Lambda zu erzeugen.

Die Idee ist, dass der LINQ-Provider in der Lage sein sollte, die Semantik dieser Operation zu verstehen und einen vernünftigen Handlungsablauf zu WHERE age >= 18 AND gender = 'Male' (zB SQL wie WHERE age >= 18 AND gender = 'Male' ).

Oft haben Provider jedoch Probleme mit InvocationExpression , weil die Verarbeitung eines "verschachtelten Ausdruck-Aufrufs innerhalb eines Ausdrucks" offensichtlich kompliziert ist.

Um dies zu umgehen, bietet LINQKit auch den Expand Helper. Dies "impliziert" den Aufrufaufruf in intelligenter Weise, indem der Aufruf durch den Rumpf des verschachtelten Ausdrucks ersetzt wird, wobei die Verwendung der Parameter des verschachtelten Ausdrucks entsprechend ersetzt wird (in diesem Fall p2 durch p1 ersetzen). Dies sollte etwa so aussehen:

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

Beachten Sie, dass Sie diese Prädikate manuell kombiniert hätten, wenn Sie es selbst in einem Lambda getan hätten. Aber mit LINQKit können Sie diese Prädikate aus unabhängigen Quellen beziehen und sie leicht kombinieren:

  1. Ohne "von Hand" Ausdruck Code schreiben.
  2. Optional in einer Weise, die für die Konsumenten des resultierenden Lambda transparent ist.


Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow