2009-10-30 2 views

Antwort

17

Die erste wird in übersetzt werden:

objectList.Where(o => o.value1 < 100).Where(o=> o.value2 > 10) 

, während die zweite wird in übersetzt werden:

objectList.Where(o => o.value1 < 100 && o.value2 > 10) 

So in der ersten, werden Sie eine erste gefilterte Folge haben, dass wird erneut gefiltert (die erste Sequenz enthält alle Objekte mit dem Wert < 100, die zweite enthält alle Objekte mit dem Wert> 10 aus der ersten Sequenz), während die zweite Sequenz dieselben Vergleiche im selben Labda-Ausdruck durchführt. Dies gilt für Linq für Objekte, für andere Anbieter hängt es davon ab, wie der Ausdruck übersetzt wird.

+1

Eigentlich ist das ziemlich ungenau. Wenn Sie 'Linq's Quellen überprüfen, werden Sie sehen, dass' Where' eine Methode hat, die '.Where (x) .Where (y)' in '.Where (x && y)' übersetzt. [Quelle] (http://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,f7e72dc9c9621f30) –

+0

Guter Punkt, ich bin nicht in der Lage zu sagen, ob ich dies im Jahr 2009 überprüft oder wenn es war die ganze Zeit wahr. – Philippe

1

Auf der grundlegendsten Ebene erhalten Sie zwei Where-Operationen statt einer. Mit Reflector können Sie am besten untersuchen, was am anderen Ende eines Abfrageausdrucks ausgegeben wird.

Ob sie auf dasselbe optimiert werden, hängt vom LINQ-Provider ab - sie muss den gesamten Baum übernehmen und in eine andere Syntax konvertieren. Bei LINQ To Objects ist dies nicht der Fall.

C# in Depth ist gut, um Ihnen ein Verständnis für dieses Thema zu geben.

6

Die erste übersetzt:

objectList.Where(o => o.value1 < 100) 
      .Where(o => o.value2 > 10); 

während letztere Sie bekommt:

objectList.Where(o => o.value1 < 100 && o.value2 > 10);  

Es ist functionnaly gleich, und während der zweite würde einen Methodenaufruf ersparen, ist der Unterschied in der Leistung Ist vernachlässigbar. Verwenden Sie, was für Sie besser lesbar ist.

Das heißt, wenn Sie Linq zu Objekten verwenden. Wenn Sie einen Provider verwenden, hängt dies davon ab, wie er implementiert wird (wenn das Prädikat in der resultierenden Abfrage nicht berücksichtigt wird, kann das Ergebnis suboptimal sein).

+0

Ich tippte es tatsächlich direkt. Du hast recht, der Identity Selector macht keinen Sinn. –

0

Wie wäre es damit für eine Antwort: mit & & können Sie nicht garantieren, dass beide Ausdrücke ausgewertet werden (wenn die erste Bedingung falsch ist, dann wird die zweite möglicherweise nicht ausgewertet). Mit den zwei Where-Klauseln kannst du das. Keine Ahnung, ob es stimmt, aber es klingt gut für mich!

+2

Ich glaube nicht, dass das stimmt. Wenn es sich um Linq to Objects handelt, gibt der erste Where-call eine Enumeration zurück, die nur die Elemente enthält, für die Bedingung 1 wahr ist. Daher wird Bedingung 2 nur für diese Elemente aufgerufen. – Niki

+0

Richtig, aber ist das Gegenteil nicht wahr? Nehmen wir an, Sie verwenden ein einfaches '&', dann werden beide im zweiten Fall ausgewertet. Wie auch immer, besser vermeiden Sie Nebenwirkungen in diesen :) – Philippe

0

Alle anderen Dinge, die gleich sind, würde ich die condition1 && condition2 Version aus Gründen der Lesbarkeit des Codes wählen.

3

Ich habe nur Profil es. kein Unterschied in SQL-Code

+0

Angenommen, das OP sprach über LINQ to SQL. =) –

6

Die markierte Antwort wird es ein wenig ungenau.

Wie @Philippe sagte, wird die erste in übersetzt werden:

objectList.Where(o => o.value1 < 100).Where(o=> o.value2 > 10) 

während der zweite in übersetzt wird:

objectList.Where(o => o.value1 < 100 && o.value2 > 10) 

AberLinq a hat wenig Optimierung für verkettete Where Aufrufe.

Wenn Sie Linq's Quellcode prüfen sehen Sie folgendes:

class WhereEnumerableIterator<TSource> : Iterator<TSource> 
{ 
    public override IEnumerable<TSource> Where(Func<TSource, bool> predicate) 
    { 
     return new WhereEnumerableIterator<TSource>(source, 
      CombinePredicates(this.predicate, predicate)); 
    } 
} 

Was CombinePredicates tut, ist, um die beiden Prädikate mit && zwischen ihnen kombiniert:

static Func<TSource, bool> CombinePredicates<TSource>(Func<TSource, bool> predicate1, 
    Func<TSource, bool> predicate2) 
{ 
    return x => predicate1(x) && predicate2(x); 
} 

So objectList.Where(X).Where(Y) entspricht objectList.Where(X && Y) abgesehen von der Erstellungszeit der Abfrage (die ohnehin extrem kurz ist) und dem Aufruf von zwei Prädikaten.

Unterm Strich ist, dass es nicht Filter oder die Sammlung zwei Mal durchlaufen - aber eine zusammengesetzte Zeit.

Verwandte Themen