Wann ist es angebracht, eine (klassische) Fall-Through-switch-Anweisung zu verwenden? Wird eine solche Verwendung empfohlen und empfohlen oder sollte sie unter allen Umständen vermieden werden?
Wann ist es angebracht, eine (klassische) Fall-Through-switch-Anweisung zu verwenden? Wird eine solche Verwendung empfohlen und empfohlen oder sollte sie unter allen Umständen vermieden werden?
Antworten:
Hier ist ein Beispiel, wo es nützlich wäre.
public Collection<LogItems> GetAllLogItems(Level level) {
Collection<LogItems> result = new Collection<LogItems>();
switch (level) {
// Note: fall through here is INTENTIONAL
case All:
case Info:
result.Add(GetItemsForLevel(Info));
case Warning:
result.Add(GetItemsForLevel(Warning));
case Error:
result.Add(GetItemsForLevel(Error));
case Critical:
result.Add(GetItemsForLevel(Critical));
case None:
}
return result;
}
Diese Art von Dingen (in denen ein Fall den anderen einschließt) ist meiner Meinung nach eher selten, weshalb einige neuere Sprachen entweder kein Fallover zulassen oder eine spezielle Syntax dafür erfordern.
// INTENTIONAL FALL THROUGH HERE
Kommentar in Großbuchstaben.
GetItemsForLevel(Info)
Anruf aufgerufen wird GetItemsForLevel(Warning)
und so weiter.
Ich benutze sie, wenn bestimmte Funktionen für mehr als einen Wert angewendet werden müssen. Angenommen, Sie hatten ein Objekt mit einer Eigenschaft namens operationCode. Wenn der Code gleich 1, 2, 3 oder 4 ist, möchten SieOperationX () starten. Wenn es 5 oder 6 ist, möchten Sie StartOperationY () und 7 Sie StartOperationZ (). Warum 7 vollständige Fälle mit Funktionen und Pausen, wenn Sie Fall-Throughs verwenden können?
Ich denke, es ist in bestimmten Situationen völlig gültig, besonders wenn es 100 if-else-Anweisungen vermeidet. =)
switch
mit mehreren case
an den gleichen Code gebundenes. Das ist etwas anderes als ein Fall-through, bei dem die Ausführung von einem case
zum nächsten fortgesetzt wird, weil break
zwischen ihnen kein Dazwischen besteht.
Durchfallkoffer sind völlig in Ordnung. Ich stelle oft fest, dass eine Aufzählung an vielen Stellen verwendet wird und dass es einfacher ist, Fall-Through-Logik zu verwenden, wenn Sie einige Fälle nicht unterscheiden müssen.
Zum Beispiel (beachten Sie die Erläuterungen):
public boolean isAvailable(Server server, HealthStatus health) {
switch(health) {
// Equivalent positive cases
case HEALTHY:
case UNDER_LOAD:
return true;
// Equivalent negative cases
case FAULT_REPORTED:
case UNKNOWN:
case CANNOT_COMMUNICATE:
return false;
// Unknown enumeration!
default:
LOG.warn("Unknown enumeration " + health);
return false;
}
}
Ich finde diese Art der Nutzung vollkommen akzeptabel.
case X: case Y: doSomething()
und gibt case X: doSomething(); case Y: doAnotherThing()
. In der ersten ist die Absicht ziemlich explizit, während in der zweiten der Durchbruch beabsichtigt sein kann oder nicht. Meiner Erfahrung nach löst das erste Beispiel in Compilern / Code-Analysatoren niemals Warnungen aus, während das zweite dies tut. Persönlich würde ich das zweite Beispiel nur als "Durchfallen" bezeichnen - ich bin mir jedoch nicht sicher, ob es sich um eine "offizielle" Definition handelt.
Es hängt davon ab:
Die zwei Hauptprobleme, die damit verbunden sind, dass ein Fall zum nächsten fällt, sind:
Es macht Ihren Code von der Reihenfolge der case-Anweisungen abhängig. Das ist nicht der Fall, wenn Sie nie durchfallen, und es fügt einen Grad an Komplexität hinzu, der oft unerwünscht ist.
Es ist nicht offensichtlich, dass der Code für einen Fall den Code für einen oder mehrere nachfolgende Fälle enthält.
Einige Orte verbieten ausdrücklich das Durchfallen. Wenn Sie an einem solchen Ort nicht arbeiten und mit dem Üben vertraut sind und wenn das Brechen des fraglichen Codes kein wirkliches Leiden verursacht, ist es möglicherweise nicht das Schlimmste auf der Welt. Wenn Sie dies dennoch tun, sollten Sie einen aufmerksamkeitsstarken Kommentar in die Nähe legen, um diejenigen zu warnen, die später kommen (einschließlich Ihrer Zukunft).
Hier ist ein kurzes (zugegebenermaßen unvollständiges (kein spezieller Umgang mit Schaltjahren)) Beispiel für einen Sturz, der mein Leben einfacher macht:
function get_julian_day (date) {
int utc_date = date.getUTCDate();
int utc_month = date.getUTCMonth();
int julian_day = 0;
switch (utc_month) {
case 11: julian_day += 30;
case 10: julian_day += 31;
case 9: julian_day += 30;
case 8: julian_day += 31;
case 7: julian_day += 31;
case 6: julian_day += 30;
case 5: julian_day += 31;
case 4: julian_day += 30;
case 3: julian_day += 31;
case 2: julian_day += 28;
case 1: julian_day += 31;
default: break;
}
return julian_day + utc_date;
}
Wenn ich das Bedürfnis habe, von einem Fall zum nächsten zu wechseln (zugegebenermaßen selten), bevorzuge ich es, sehr explizit zu sein, und das goto case
setzt natürlich voraus, dass Ihre Sprache dies unterstützt.
Da das Durchfallen so ungewöhnlich und beim Lesen von Code sehr leicht zu übersehen ist, ist es meiner Meinung nach angebracht, explizit zu sein - und ein Goto sollte, selbst wenn es sich um einen Fall handelt, wie ein Daumenschmerzen auffallen.
Es hilft auch, Fehler zu vermeiden, die auftreten können, wenn case-Anweisungen neu angeordnet werden.