Geeignete Verwendung von Fall-Through-Switch-Anweisungen

14

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?

shabunc
quelle
Nicht alle Sprachen erlauben das Durchfallen von switch-Anweisungen.
Oded
@Oded, bearbeitet, hinzugefügt "klassisches" Wort. Nicht alle Sprachen erlauben fallen durch, dennoch bestehe ich es klassisch)
shabunc
3
Wenn Sie über das Gerät von Duffs sprechen , ist das eine Sache.
Oded
6
@Oded: Das ist das Erste, woran die meisten Leute denken, aber das ist kaum "angemessen". Nach dieser , Duff selbst sagte „Dies ist definitiv ein Argument in der Diskussion stellt , ob der Schalter standardmäßig durchfallen sollte, aber ich bin mir nicht sicher , ob das Argument für oder gegen sie ist.“
BlueRaja - Danny Pflughoeft

Antworten:

15

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.

Konfigurator
quelle
13
Dieses Beispiel ist zwar interessant, es fehlt jedoch der erforderliche // INTENTIONAL FALL THROUGH HEREKommentar in Großbuchstaben.
Russell Borogove
Es ist genauso einfach, diesen Code zu schreiben, indem der GetItemsForLevel(Info)Anruf aufgerufen wird GetItemsForLevel(Warning)und so weiter.
Caleb
@ RussellBorogove: Absolut richtig.
Konfigurator
@Caleb: In diesem Fall ja. Aber was wäre, wenn die Anrufe etwas komplizierter wären? Es könnte ein bisschen haarig werden, während der Durchfall es einfach erscheinen lässt. Ich sollte beachten, dass ich eigentlich nicht für die Verwendung von Fall Through bin - ich sage nur, dass es in bestimmten Situationen nützlich sein kann.
Konfigurator
Nicht das beste Beispiel. Es gibt eine Reihenfolge der Warnstufen. Durch Definieren dieser Reihenfolge wird diese Methode auf eine einzelne Zeile von Code-Filterelementen reduziert, wenn die Elementebene mindestens der gewünschten Ebene entspricht.
Kevin Cline
8

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. =)

Yatrix
quelle
4
Was Sie beschreiben, ist ein switchmit mehreren casean den gleichen Code gebundenes. Das ist etwas anderes als ein Fall-through, bei dem die Ausführung von einem casezum nächsten fortgesetzt wird, weil breakzwischen ihnen kein Dazwischen besteht.
Blrfl
3
Es ist eigentlich egal, der Fall-through ist nur das Fehlen einer break-Anweisung, so dass es zum nächsten Fall "durchfällt".
Yatrix
Ich würde das Szenario in Ihrer Antwort umformulieren, um dies widerzuspiegeln.
Blrfl
2
@ Yatrix: Ich bin anderer Meinung. Aufeinanderfolgende Fälle, in denen genau derselbe Codeblock ausgeführt wird, unterscheiden sich erheblich davon, einen Umbruch auszulassen. Das eine ist Routine, das andere ist weit davon entfernt (ime) - und das Risiko von Fehlinterpretationen und unbeabsichtigten Kontrollabläufen ist viel größer.
Quentin-Starin
3
@qes ja, es ist anders, aber sie sind beide Durchbrüche. Er fragte, wann / ob es angemessen sei. Ich gab ein Beispiel dafür, wann es sein würde. Es sollte kein All-Inclusive-Beispiel sein. Je nach Sprache funktionieren Aussagen vor einem Fall-through möglicherweise nicht. Ich glaube nicht, dass dies bei C # stackoverflow.com/questions/174155/…
Yatrix
8

Ich habe sie gelegentlich benutzt, ich denke, es ist immer eine angemessene Verwendung - aber nur, wenn der entsprechende Kommentar beigefügt ist.

gbjbaanb
quelle
7

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.

Bringer128
quelle
Beachten Sie, dass es einen großen Unterschied zwischen 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.
Jens Bannmann
6

Es hängt davon ab:

  • Ihre persönlichen Vorlieben
  • Kodierungsstandards Ihres Arbeitgebers
  • die Höhe des Risikos

Die zwei Hauptprobleme, die damit verbunden sind, dass ein Fall zum nächsten fällt, sind:

  1. 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.

  2. 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).

Caleb
quelle
4

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;
}
AaronDanielson
quelle
5
Das ist zwar klug, aber die Zeit, die Sie dadurch sparen, wird weitaus höher sein als die Zeit, die andere Menschen benötigen, um herauszufinden, was dies bewirkt. Sie können auch eine bessere Leistung erzielen, indem Sie den Fall-Through-Aspekt entfernen, dh 31 + 28 + 31 ist immer 90. Wenn Sie dies tun, können Sie auch einfach die Summen in die Fälle eintragen, da nur 11 zu berücksichtigen sind.
JimmyJames
Sie haben Recht, mein Beispiel ist definitiv erfunden :) Ich werde jedoch sagen, dass es einfacher ist, einen versteckten Fehler zu erkennen, wenn die Anzahl der Tage wie folgt angegeben wird, anstatt alle kumulierten Tage für jeden Fall des Wechsels vorab zu berechnen .
AaronDanielson
2
Ich gebe Ihnen das zu, aber dies in einer konstanten Deklaration zu tun wäre vorzuziehen, zB FEB_START = 31; MAR_START = FEB_START + 28; usw. nicht sicher, welche Sprache dies ist, aber in vielen Fällen würde es beim Kompilieren berechnet werden. Das größere Problem hier ist, dass es ein wenig stumpf ist. Nicht so sehr, dass es eine schlechte Idee wäre, nur untypisch. Wenn es keinen wirklich großen Vorteil gibt, ist es im Allgemeinen besser, sich an gängige Redewendungen zu halten.
JimmyJames
1
Hervorragende Alternative mit Konstanten für Starttage in diesem Beispiel. Der Punkt hier ist jedenfalls, dass eine kumulative Summe eine großartige Verwendung für einen Switch-Case-Fall-Through ist. Ich bin zu 100% damit einverstanden, gemeinsame Redewendungen zu verwenden, aber die Natur dieser Frage wagt sich in die esoterischeren Merkmale, in denen gemeinsame Redewendungen schwer zu finden sind.
AaronDanielson
3

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 casesetzt 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.

Quentin-Starin
quelle