2013-07-19 4 views
19

fand ich (grob) diesen Code in das Enumerable.Single Verfahren, während es mit einigen Decompiler Inspektion:Warum wird Single() nicht direkt zurückgegeben, wenn mehr als ein Element gefunden wird?

foreach (TSource current in source) 
{ 
    if (predicate(current)) 
    { 
     result = current; 
     num += 1L; 
    } 
} 

if (num > 1L) 
{ 
    throw Error.MoreThanOneMatch(); 
} 

Wie Sie sehen können, ist es über alle Elemente Schleifen vor dem Wurf. Warum bricht es nicht wenn num > 1?

+0

Vielen Dank für diese Frage. Es ist wirklich interessant, warum sich das LINQ-Team dafür entschieden hat, hier bis zum Ende zu laufen. –

+0

Vince, gibt es einen Unterschied zwischen Enumerable.Single und Queryable.Single Implementierungen in diesem Teil? –

+4

Wo haben Sie diese Implementierung gefunden? Mit Reflector sehe ich etwas völlig anderes, das * sofort * zurückkehrt, wenn ein zweites Element gefunden wird. –

Antwort

4

Agree, dass es von Sachen Leistung besser sein wird (EDIT: Wenn wir unser Prädikat mehr als ein Element passend zu erwarten, was wir nicht tun sollten):

foreach (TSource current in source) 
{ 
    if (predicate(current)) 
    { 
     result = current; 
     num += 1L; 

     if (num > 1L) 
      throw Error.MoreThanOneMatch(); 
    } 
} 

if (num == 0L) 
    throw Error.NoMatch(); 

return local; 

Sieht aus wie sie beschlossen zu machen Ergebnisse analysieren klarer und trennte es von der Aufzählung der Quelle. Aber dann frage ich mich, warum einfache Schalter nicht verwendet wurden:

switch((int)num) 
{ 
    case 0: throw Error.NoMatch(); 
    case 1: return local; 
    default: 
     throw Error.MoreThanOneMatch();  
} 

In Bezug auf Performance-Probleme - ich denke, es ist angenommen, dass Single sollte aufgerufen werden, wenn Sie sind wirklich einzelnes Ergebnis erwarten. Null oder mehr Ergebnisse ist ein Ausnahmepfad, der nicht häufig vorkommen sollte (wie jede Ausnahme). Es ist also mehr der logische Fehler Ihres Programms, wenn die Quelle viele Elemente enthält, die mit dem Prädikat übereinstimmen.

+0

Ich denke, Ihre Switch-Lösung muss die gesamte Quelle aufzählen. Die aktuelle Lösung mit if löst jedoch sofort eine Ausnahme aus, wenn sie weiß, dass eine Duplizität vorliegt. – Ondra

+0

@Ondra aktuelle Lösung löst keine Ausnahme sofort aus. Schauen Sie sich den Quellcode an. Und mein Switch-Block ist ein umstrukturierter "num" -Analysierblock aus der ursprünglichen Implementierung. Dieser Schalter sollte nach dem Aufzählen platziert werden –

0

Von Single ist gemeint, genau eine, nicht keine und auch nicht mehr als eine.
Es zählt alle Artikel, um sicherzustellen, dass es nur eine ist.
Es wird eine Ausnahme ausgelöst, wenn es keine oder mehr als eine gibt.
SingleOrDefault stattdessen wirft, wenn es mehr gibt, aber default(T)/null zurückgibt, wenn es keine gibt.

Was Sie suchen, ist FirstOrDefault, die die Aufzählung bricht, wenn es die erste passend zum Prädikat fand. First wirft stattdessen, wenn es keine gibt, und bricht auch (direkt zurück) es ist foreach, wenn es den ersten gefunden hat.

FirstOrDefault der Quelle

foreach (TSource current in source) 
{ 
    if (predicate(current)) 
    { 
     return current; 
    } 
} 
return default(TSource); 

Während Erste der Quelle statt Rückkehr Standard ist

throw Error.NoMatch(); 
+0

Das war mein erster Gedanke, aber die Frage ist, warum, wenn 2 übereinstimmende Elemente gefunden werden, eine Ausnahme nicht an diesem Punkt ausgelöst wird, anstatt durch den Rest der Liste zu iterieren und dann die Ausnahme zu werfen? – keyboardP

+0

Sorry, mein Fehler, 'SingleOrDefault' wirft niemals, es gibt null zurück, wenn mehr oder keine vorhanden sind. 'Single' ist derjenige, der wirft. – metadings

+1

Meine Vermutung ist: Sie wollten die Iteration vor dem Werfen und Ausnahme beenden. Wenn sie eine Ausnahme in der Mitte der Aufzählung werfen, könnte es einige Nebeneffekte verursachen - zB Ihr Enumerator.Next lädt ein Element aus dem Internet herunter und mit der Ausnahme, dass die Verbindung nicht richtig geschlossen ist. – Ondra

Verwandte Themen