2010-09-07 10 views
6

Ich habe ein Stück Code für einige logische Validierung, die geht verallgemeinert in für wie folgt aus:LINQ oder foreach - Stil/Lesbarkeit und Geschwindigkeit

private bool AllItemsAreSatisfactoryV1(IEnumerable<Source> collection) 
{ 
    foreach(var foo in collection) 
    { 
     Target target = SomeFancyLookup(foo); 
     if (!target.Satisfactory) 
     { 
      return false; 
     } 
    } 
    return true; 
} 

Das funktioniert, ist recht einfach zu verstehen, und hat früh -out Optimierung. Es ist jedoch ziemlich ausführlich. Der Hauptzweck dieser Frage ist, was als lesbar und guter Stil gilt. Ich bin auch an der Aufführung interessiert; Ich bin fest davon überzeugt, dass vorzeitige {Optimierung, Pessimisierung} ist die Wurzel allen Übels, und versuchen, Mikro-Optimierung zu vermeiden sowie Engpässe einzuführen.

Ich bin ziemlich neu bei LINQ, also hätte ich gerne ein paar Kommentare zu den beiden alternativen Versionen, die ich mir ausgedacht habe, sowie alle anderen Vorschläge. Lesbarkeit.

private bool AllItemsAreSatisfactoryV2(IEnumerable<Source> collection) 
{ 
    return null == 
     (from foo in collection 
     where !(SomeFancyLookup(foo).Satisfactory) 
     select foo).First(); 
} 

private bool AllItemsAreSatisfactoryV3(IEnumerable<Source> collection) 
{ 
    return !collection.Any(foo => !SomeFancyLookup(foo).Satisfactory); 
} 

Ich glaube nicht, dass V2 bietet viel über V1 in Bezug auf Lesbarkeit, auch wenn kürzer. Ich finde V3 klar zu sein & prägnant, aber ich bin nicht allzu lieb der Method().Property Teil; natürlich könnte ich das Lambda in einen vollen Delegierten verwandeln, aber dann verliert es seine Einlinien-Eleganz.

Was Ich mag würde Kommentare zu sind:

  1. Style - immer so subjektiv, aber was fühlen Sie lesbar ist?
  2. Leistung - sind irgendwelche von diesen ein definitives Nein-Nein? Soweit ich es verstehe, sollten alle drei Methoden frühzeitig auslaufen.
  3. Debuggability - alles zu berücksichtigen?
  4. Alternativen - alles geht.

Vielen Dank im Voraus :)

+2

Wenn ich LINQ lese, kann ich niemals den Sinn der "natürlichen Sprache" verstehen (all 'von x in xs select ... '). Die 'xs.Select (x => ...)' Version erscheint immer klarer und macht mehr Sinn für mich (aber dann bin ich es nur). V3 ist für mich am lesbarsten. –

+0

@ Callum Rogers: Ich fühle mich ziemlich ähnlich; Leute, die viel SQL machen, könnten sich jedoch anders fühlen :) – snemarch

Antwort

12

denke ich All klarer sein würde:

private bool AllItemsAreSatisfactoryV1(IEnumerable<Source> collection) 
{ 
    return collection.Select(f => SomeFancyLookup(f)).All(t => t.Satisfactory); 
} 

Ich denke, es ist unwahrscheinlich, Linq ist mit hier würde ein Leistungsproblem über eine reguläre foreach-Schleife hat, die aber würde es einfach zu ändern, wenn es so wäre.

+0

Einverstanden - keine Notwendigkeit für Negationen, und es wird immer noch früh beendet, wenn es einen unbefriedigenden Gegenstand findet. –

+0

In .NET 4 können Sie es sogar noch weiter vereinfachen: 'return collection.Select (SomeFancyLookup) .Alle (t => t.Satisfactory);' –

+0

@Joel - Die gleiche Syntax ist legal in 3.5; SomeFancyLookup wird zu einem Delegaten mit einer bekannten Methodensignatur. – KeithS

1

Ich persönlich habe kein Problem mit dem Stil der V3, und das wäre meine erste Wahl. Sie suchen im Wesentlichen nach der Liste für alle, deren Nachschlagen nicht zufriedenstellend ist.

V2 ist schwer zu verstehen, die Absicht, und in seiner aktuellen Form wird eine Ausnahme (First() erfordert die Quelle IEnumerable nicht leer sein; Ich denke, Sie suchen nach FirstOrDefault()). Warum nicht einfach Any() am Ende anheften, anstatt ein Ergebnis von der Liste mit null zu vergleichen?

V1 ist in Ordnung, wenn ein bisschen redselig, und wahrscheinlich am einfachsten zu debuggen, wie ich festgestellt habe, Debugging Lambdas zu etwas pingelig manchmal. Sie können die inneren Klammern entfernen, um einige Leerzeichen zu verlieren, ohne die Lesbarkeit zu beeinträchtigen.

Wirklich, alle drei werden in sehr ähnliche Opcodes herunterkochen; Iterieren Sie die Auflistung, rufen Sie SomeFancyLookup() auf, und überprüfen Sie eine Eigenschaft ihres Rückgabewerts. raus mit dem ersten Fehler. Any() "versteckt" einen sehr ähnlichen foreach-Algorithmus. Der Unterschied zwischen V1 und allen anderen ist die Verwendung einer benannten Variablen, die etwas weniger leistungsfähig sein könnte, aber Sie haben in allen drei Fällen einen Bezug zu einem Ziel, so dass ich bezweifle, dass es signifikant ist, wenn ein Unterschied überhaupt existiert.

+0

"Warum nicht einfach Any() am Ende" - oh! Danke auch für die Ausnahmewarnung. Ein sehr ähnlicher IL-Code wird tatsächlich für die beiden LINQ-Versionen erzeugt, wobei die "Natural Language" -Version einen zusätzlichen Aufruf aufweist. – snemarch