Sollte ich in meiner LINQ-Abfrage zwei "where" -Klauseln oder "&&" verwenden?

75

Sollte ich beim Schreiben einer LINQ-Abfrage mit mehreren "und" -Bedingungen eine einzelne whereKlausel &&oder mehrere whereKlauseln schreiben , eine für jede Bedingung?

static void Main(string[] args)
{
    var ints = new List<int>(Enumerable.Range(-10, 20));

    var positiveEvensA = from i in ints
                         where (i > 0) && ((i % 2) == 0)
                         select i;

    var positiveEvensB = from i in ints
                         where i > 0
                         where (i % 2) == 0
                         select i;

    System.Diagnostics.Debug.Assert(positiveEvensA.Count() == 
                                         positiveEvensB.Count());
}

Gibt es einen anderen Unterschied als die persönlichen Vorlieben oder den Codierungsstil (lange Zeilen, Lesbarkeit usw.) zwischen positiveEvensA und positiveEvensB ?

Ein möglicher Unterschied besteht darin, dass verschiedene LINQ-Anbieter möglicherweise besser mit mehreren wheres umgehen können als mit einem komplexeren Ausdruck. Ist das wahr?

Nаn
quelle

Antworten:

52

Ich persönlich würde immer mit den && vs. zwei where-Klauseln gehen, wenn dies die Aussage nicht unverständlich macht.

In Ihrem Fall wird es wahrscheinlich überhaupt nicht auffallen, aber 2 where-Klauseln haben definitiv Auswirkungen auf die Leistung, wenn Sie über eine große Sammlung verfügen und alle Ergebnisse dieser Abfrage verwenden. Wenn Sie beispielsweise .Count () für die Ergebnisse aufrufen oder die gesamte Liste durchlaufen, wird die erste where-Klausel ausgeführt, wodurch eine neue IEnumerable erstellt wird, die mit einem zweiten Delegaten erneut vollständig aufgelistet wird.

Wenn Sie die beiden Klauseln miteinander verketten, bildet die Abfrage einen einzelnen Delegaten, der ausgeführt wird, wenn die Auflistung aufgelistet wird. Dies führt zu einer Aufzählung durch die Sammlung und einem Aufruf an den Delegaten jedes Mal, wenn ein Ergebnis zurückgegeben wird.

Wenn Sie sie teilen, ändern sich die Dinge. Während Ihre erste where-Klausel die ursprüngliche Sammlung auflistet, listet die zweite where-Klausel die Ergebnisse auf. Dies führt möglicherweise (im schlimmsten Fall) zu 2 vollständigen Aufzählungen in Ihrer Sammlung und zu 2 Delegierten pro Mitglied, was bedeuten könnte, dass diese Anweisung (theoretisch) das Zweifache der Laufzeitgeschwindigkeit benötigt.

Wenn Sie sich für die Verwendung von 2 where-Klauseln entscheiden, hilft es sehr, die restriktivere Klausel an die erste Stelle zu setzen, da die zweite where-Klausel nur für die Elemente ausgeführt wird, die die erste Klausel übergeben.

In Ihrem Fall spielt dies keine Rolle. Bei einer großen Sammlung könnte es sein. Als allgemeine Faustregel gehe ich für:

1) Lesbarkeit und Wartbarkeit

2) Leistung

In diesem Fall sind beide Optionen meiner Meinung nach gleichermaßen wartbar, daher würde ich mich für die leistungsfähigere Option entscheiden.

Reed Copsey
quelle
37
Mit 2 "where" -Klauseln ist dies immer noch nur eine einzelne Iteration mit 2 Delegatenaufrufen pro Element - nicht wie behauptet 2 Iterationen.
Marc Gravell
5
Marc, wenn ich zwei Iterationen sage, hätte ich expliziter sein sollen. Mit 2 where-Klauseln konstruieren Sie zwei separate Enumeratoren - der erste, bei dem ein Enumerator erstellt wird, der vom zweiten aufgezählt wird. Aber das ist ziemlich klein - es werden keine 2 Schleifen ausgeführt, sondern nur mit separaten Enumeratoren.
Reed Copsey
3
Ich denke, es Wheregibt einige spezielle Optimierungen für den Fall der multiplen where-Klausel. Trotzdem wird es aufgrund der Aufrufe mehrerer Delegierter langsamer.
CodesInChaos
21

Dies ist meistens ein persönliches Stilproblem. Persönlich wheregruppiere ich die Klauseln , solange die Klausel in eine Zeile passt.

Die Verwendung mehrerer wheres ist in der Regel weniger leistungsfähig, da für jedes Element, das es so weit bringt, ein zusätzlicher Delegatenaufruf erforderlich ist. Es handelt sich jedoch wahrscheinlich um ein unbedeutendes Problem, das nur berücksichtigt werden sollte, wenn ein Profiler dies als Problem anzeigt.

JaredPar
quelle
1

Wie andere vorgeschlagen haben, ist es eher eine persönliche Präferenz. Ich mag die Verwendung von &&, da es besser lesbar ist und die Syntax anderer Mainstream-Sprachen nachahmt.

DotnetDude
quelle