Ich habe diese Art von Funktion oft in beiden Formaten geschrieben und mich gefragt, ob ein Format einem anderen vorgezogen wird und warum.
public void SomeFunction(bool someCondition)
{
if (someCondition)
{
// Do Something
}
}
oder
public void SomeFunction(bool someCondition)
{
if (!someCondition)
return;
// Do Something
}
Normalerweise codiere ich mit dem ersten, da mein Gehirn beim Codieren so arbeitet, obwohl ich den zweiten vorzuziehen denke, da er sich sofort um die Fehlerbehandlung kümmert und das Lesen erleichtert
Antworten:
Ich bevorzuge den zweiten Stil. Schieben Sie ungültige Fälle zuerst aus dem Weg, indem Sie sie entweder beenden oder gegebenenfalls Ausnahmen auslösen, setzen Sie eine Leerzeile ein und fügen Sie dann den "echten" Hauptteil der Methode hinzu. Ich finde es leichter zu lesen.
quelle
Auf jeden Fall das letztere. Ersteres sieht im Moment nicht schlecht aus, aber wenn Sie komplexeren Code erhalten, kann ich mir nicht vorstellen, dass irgendjemand dies denken würde:
ist besser lesbar als
Ich gebe zu, ich habe den Vorteil einzelner Ausstiegspunkte nie verstanden.
quelle
return value;
hilft!?! Dann muss man ein halbes Dutzend jagenvalue = ...
, mit dem Nachteil, dass man nie sicher ist, dass sich der Wert zwischen dieser Aufgabe und der endgültigen Rückgabe nicht ändert. Zumindest eine sofortige Rückkehr ist klar, dass nichts mehr das Ergebnis verändern wird.Es kommt darauf an - Im Allgemeinen werde ich nicht allzu sehr versuchen, eine Reihe von Code zu verschieben, um die Funktion frühzeitig zu beenden - der Compiler kümmert sich im Allgemeinen darum. Das heißt aber, wenn es oben einige grundlegende Parameter gibt, die ich brauche und ansonsten nicht weitermachen kann, werde ich früh ausbrechen. Ebenso, wenn eine Bedingung einen Riesenblock
if
in der Funktion erzeugt, werde ich es als Ergebnis auch früh ausbrechen lassen.Das heißt, wenn eine Funktion beim Aufrufen einige Daten benötigt, werde ich normalerweise eine Ausnahme auslösen (siehe Beispiel), anstatt nur zurückzukehren.
quelle
Ich bevorzuge die vorzeitige Rückkehr.
Wenn Sie einen Einstiegs- und einen Ausstiegspunkt haben, müssen Sie immer den gesamten Code in Ihrem Kopf bis zum Ausstiegspunkt verfolgen (Sie wissen nie, ob ein anderes Stück Code unter dem Ergebnis noch etwas anderes bewirkt, also Sie müssen es aufspüren, bis das existiert). Sie tun das, egal welcher Zweig das Endergebnis bestimmt. Dies ist schwer zu folgen.
Wenn ein Eintrag und mehrere vorhanden sind, kehren Sie zurück, wenn Sie Ihr Ergebnis haben, und verfolgen es nicht bis zum Ende, um festzustellen, dass niemand etwas anderes daran tut (da es seit Ihrer Rückkehr nichts anderes mehr gibt). Es ist, als würde man den Methodenkörper in mehrere Schritte aufteilen, wobei jeder Schritt die Möglichkeit bietet, das Ergebnis zurückzugeben oder den nächsten Schritt sein Glück versuchen zu lassen.
quelle
Bei der C-Programmierung, bei der Sie manuell bereinigen müssen, gibt es eine Menge zu sagen für die Ein-Punkt-Rückgabe. Auch wenn es derzeit nicht erforderlich ist, etwas zu bereinigen, kann jemand Ihre Funktion bearbeiten, etwas zuweisen und es vor der Rückgabe bereinigen. In diesem Fall wird es ein Albtraum sein, alle Rückgabeanweisungen durchzusehen.
In der C ++ - Programmierung gibt es Destruktoren und sogar jetzt Scope-Exit-Guards. All dies muss vorhanden sein, um sicherzustellen, dass der Code in erster Linie ausnahmesicher ist. Code ist also gut gegen vorzeitiges Beenden geschützt und hat daher keinen logischen Nachteil und ist lediglich ein Stilproblem.
Ich weiß nicht genug über Java, ob "finally" -Blockcode aufgerufen wird und ob Finalizer die Situation bewältigen können, die erforderlich ist, um sicherzustellen, dass etwas passiert.
C # Ich kann auf keinen Fall antworten.
D-language bietet Ihnen die richtigen eingebauten Scope-Exit-Guards und ist daher gut auf ein frühzeitiges Verlassen vorbereitet und sollte daher kein anderes Problem als den Stil darstellen.
Funktionen sollten natürlich nicht so lang sein, und wenn Sie eine große switch-Anweisung haben, wird Ihr Code wahrscheinlich auch schlecht berücksichtigt.
quelle
goto
und möglicherweise eine Zweipunktrückgabe. Beispiel (Code-Formatierung in Kommentaren nicht möglich):foo() { init(); if (bad) goto err; bar(); if (bad) goto err; baz(); return 0; err: cleanup(); return 1; }
Frühe Rückkehr zum Sieg. Sie können hässlich wirken, aber viel weniger hässlich als große
if
Verpackungen, insbesondere wenn mehrere Bedingungen zu prüfen sind.quelle
Ich benutze beides.
Wenn
DoSomething
es sich um 3-5 Codezeilen handelt, sieht der Code mit der ersten Formatierungsmethode einfach nur gut aus.Aber wenn es viel mehr Zeilen als das hat, dann bevorzuge ich das zweite Format. Ich mag es nicht, wenn sich die öffnende und schließende Klammer nicht auf demselben Bildschirm befinden.
quelle
Ein klassischer Grund für Single-Entry-Single-Exit ist, dass ansonsten die formale Semantik unaussprechlich hässlich wird (der gleiche Grund, warum GOTO als schädlich eingestuft wurde).
Anders ausgedrückt, es ist einfacher zu überlegen, wann Ihre Software die Routine beendet, wenn Sie nur 1 Rückkehr haben. Das ist auch ein Argument gegen Ausnahmen.
Normalerweise minimiere ich den Early-Return-Ansatz.
quelle
Persönlich bevorzuge ich zu Beginn die Prüfung auf Bestehen / Nichtbestehen. Dadurch kann ich die meisten der häufigsten Fehler ganz oben in der Funktion mit dem Rest der folgenden Logik zusammenfassen.
quelle
Es hängt davon ab, ob.
Vorzeitige Rückkehr, wenn eine offensichtliche Sackgasse vorliegt, auf die sofort geprüft werden muss, und die Ausführung des Restes der Funktion sinnlos machen würde. *
Stellen Sie Retval + Single Return ein, wenn die Funktion komplexer ist und andernfalls mehrere Exit Points haben könnte (Lesbarkeitsproblem).
* Dies kann häufig auf ein Designproblem hinweisen. Wenn Sie feststellen, dass viele Ihrer Methoden einen externen / paramater-Status oder dergleichen überprüfen müssen, bevor Sie den Rest des Codes ausführen, sollte dies wahrscheinlich vom Aufrufer behandelt werden.
quelle
Fred
des Fensters bereits vorhanden. Wenn SieFred
den Namen des Steuerelements auf den aktuellen Status setzen, wird ein Neuzeichnen erzwungen (was in einigen Fällen möglicherweise hilfreich ist) ärgerlich in der einen Hand), wäre es völlig vernünftig, die Set-Name-Methode vorzeitig zu beenden, wenn der alte und der neue Name übereinstimmen.Verwenden Sie ein If
In Don Knuths Buch über GOTOs habe ich gelesen, dass er in einer if-Anweisung immer den wahrscheinlichsten Zustand an erster Stelle hat. Unter der Annahme, dass dies immer noch eine vernünftige Idee ist (und nicht aus reiner Rücksicht auf die Geschwindigkeit der Ära). Ich würde sagen, frühe Rückgaben sind keine gute Programmierpraxis, insbesondere angesichts der Tatsache, dass sie häufig zur Fehlerbehandlung verwendet werden, es sei denn, Ihr Code scheitert eher als nicht :-)
Wenn Sie den obigen Hinweisen folgen, müssen Sie diese Rückgabe am Ende der Funktion einfügen, und dann können Sie sie dort auch gar nicht als Rückgabe bezeichnen. Setzen Sie einfach den Fehlercode und geben Sie sie in zwei Zeilen zurück. Dadurch wird das Ideal 1 Einfahrt 1 Ausfahrt erreicht.
Delphi-spezifisch ...
Ich bin der Meinung, dass dies eine gute Programmierpraxis für Delphi-Programmierer ist, obwohl ich keinen Beweis habe. Vor D2009 haben wir keinen atomaren Weg, um einen Wert zurückzugeben, wir haben
exit;
undresult := foo;
oder wir könnten einfach Ausnahmen auslösen.Wenn du ersetzen müsstest
zum
Sie könnten es einfach satt haben, das an der Spitze jeder Ihrer Funktionen zu sehen und es vorzuziehen
und nur
exit
ganz vermeiden .quelle
if true then Exit(foo);
ich oft die Technik verwende, um zuerstresult
aufnil
bzw. zu initialisierenFALSE
, dann alle Fehlerbedingungen zu überprüfen und nur,Exit;
ob eine erfüllt ist. Der Erfolgsfallresult
wird dann (typischerweise) irgendwo am Ende der Methode festgelegt.Ich stimme der folgenden Aussage zu:
Entnommen aus dieser Frage im Stackoverflow .
quelle
Ich verwende heutzutage fast ausschließlich frühe Renditen, und zwar im Extremfall. Ich schreibe das
wie
aber es ist wirklich egal. Wenn Ihre Funktionen mehr als eine oder zwei Verschachtelungsebenen enthalten, müssen diese aufgelöst werden.
quelle
Ich würde lieber schreiben:
quelle
DoSomeFunctionIfSomeCondition
?Wie du schreibe ich normalerweise die erste, bevorzuge aber die letzte. Wenn ich viele verschachtelte Überprüfungen habe, refactor ich normalerweise zur zweiten Methode.
Mir gefällt nicht, wie die Fehlerbehandlung von der Prüfung wegbewegt wird.
Ich bevorzuge das:
quelle
Die Bedingungen oben werden "Vorbedingungen" genannt. Indem Sie setzen
if(!precond) return;
, listen Sie visuell alle Voraussetzungen auf.Die Verwendung des großen "if-else" -Blocks kann den Einrückungsaufwand erhöhen (ich habe das Zitat über dreistufige Einrückungen vergessen).
quelle
Ich ziehe es vor, wenn Aussagen klein sind.
Wählen Sie also zwischen:
und
Ich würde wählen, was Sie als "frühe Rückkehr" beschrieben haben.
Wohlgemerkt, ich kümmere mich nicht um frühe Rückgaben oder was auch immer, ich mag es einfach, den Code zu vereinfachen, die Textkörper von if-Anweisungen zu verkürzen usw.
Verschachtelt, wenn's und für's und für's schrecklich sind , meide sie um jeden Preis.
quelle
Wie andere sagen, kommt es darauf an. Für kleine Funktionen, die Werte zurückgeben, kann ich frühe Rückgaben codieren. Bei umfangreichen Funktionen möchte ich jedoch immer einen Platz im Code haben, an dem ich weiß, dass ich etwas einfügen kann, das ausgeführt wird, bevor es zurückkehrt.
quelle
Ich übe auf Funktionsebene ausfallsicher. Es hält den Code konsistent und sauber (für mich und die, mit denen ich gearbeitet habe). Aus diesem Grund komme ich immer früh zurück.
Für einige häufig geprüfte Bedingungen können Sie Aspekte für diese Prüfungen implementieren, wenn Sie AOP verwenden.
quelle