2017-06-30 4 views
4

Ich weiß, dass, wenn ich && oder || Operatoren zusammen in der gleichen Anweisung ketten, C# aufhören wird, die Anweisung zu berechnen und das entsprechende Ergebnis zurückgibt, wenn es einen Ausdruck evaluiert und egal was die folgenden Ausdrücke sind, wird das Ergebnis nicht ändern. Zum Beispiel:Beendet die C# LINQ-Aggregatmethode die Ausführung, sobald das Ergebnis nicht mehr geändert werden kann?

var result = false && foo() && bar(); 

In dieser Erklärung foo() und bar() nie da der Ausdruck ausgeführt werden sollen zunächst falsch ist. Meine Frage ist, wird die Enumerable.Aggregate<TSource, TAccumulate> das Gleiche tun, wenn über eine Liste von Bools lief oder wird es alle Ausdrücke unabhängig bewerten? Zum Beispiel:

var result = new List<bool> 
{ 
    false, 
    foo(), 
    bar() 
}.Aggregate(true, (acc, x) => acc && x); 
+2

Der Begriff ist "Kurzschlussauswertung" – Erix

+0

'Aggregate()' iteriert über das gesamte Aufzählungszeichen. –

+0

Nein, die Akkumulationsfunktion ist für Aggregat undurchsichtig, sodass sie die gesamte Sequenz konsumieren muss. – Lee

Antwort

5

Der && Operator in Ihrem Beispiel wird kurzgeschlossen, ja. x wird zu keiner Zeit ausgewertet acc ist false.

Natürlich muss das gesamte Prädikat für jedes Element ausgeführt werden. Aggregate hat keine Möglichkeit zu wissen, dass spätere Ausführungen davon den aggregierten Wert nicht ändern werden.

Ihre Aggregationsfunktion auf dem Datensatz einen All Betrieb tatsächlich durchführt, und wenn Sie den All Betrieb verwenden, anstatt die allgemeinere Aggregate, ist es in der Lage zu bestimmen, sobald ein bestimmtes Prädikat false, dass die Das Ergebnis ist bekannt und kann nicht geändert werden, und das Prädikat muss für die verbleibenden Elemente nicht aufgerufen werden (ebenso wie Or, wenn ein true Wert gefunden wird).

+2

Seltsames Abstimmungsmuster ... Scheint so, als ob die Wähler nicht wirklich verstehen, was hier vor sich geht. –

0

Wie andere Antworten gezeigt haben, wird Ihr Aggregat-Aufruf über die gesamte Sammlung iterieren, aber die & & bei jedem Anruf wird kurzgeschlossen. Hier ist ein Beispiel, das dies veranschaulichen könnte:

Sie können sehen, dass in result1, es endet zu bewerten x(), sobald es ein falsches Ergebnis erhält. Dies ist wegen Kurzschlüssen auf acc.

In result2 haben wir uns rechts von & & bewegt und erzwingt, dass x() in allen Fällen ausgewertet wird.

Console.WriteLine("acc && x()"); 
var result1 = new List<Func<bool>> 
{ 
    () => {Console.WriteLine("One"); return true;}, 
    () => {Console.WriteLine("Two"); return false;}, 
    () => {Console.WriteLine("Three"); return false;} 
}.Aggregate(true, (acc, x) => acc && x()); 
Console.WriteLine(); 
Console.WriteLine("x() && acc"); 
var result2 = new List<Func<bool>> 
{ 
    () => {Console.WriteLine("One"); return true;}, 
    () => {Console.WriteLine("Two"); return false;}, 
    () => {Console.WriteLine("Three"); return false;} 
}.Aggregate(true, (acc, x) => x() && acc); 

Ausgang:

acc && x() 
One 
Two 

x() && acc 
One 
Two 
Three 
0

Nun in Theorie, der Compiler könnte die Aggregate() in-line, die Lambda nehmen und sie in die inlined Aggregate zu integrieren, und dann der Optimierer könnte das frühzeitige Potenzial erkennen.

Der Zweifel der aktuelle C# -Compiler-Optimierer ist irgendwo in der Nähe, dass so aggressiv, glaube ich nicht, dass so etwas geplant ist, aber es ist immer eine Möglichkeit.

Verwandte Themen