switch-Anweisung - behandelt den Standardfall, wenn er nicht erreicht werden kann

14

Wenn ich eine switch-Anweisung verwende, um Werte aus einer Aufzählung (die meiner Klasse gehört) zu verarbeiten, und für jeden möglichen Wert eine Groß- / Kleinschreibung habe, lohnt es sich, Code hinzuzufügen, um den "Standard" -Fall zu behandeln?

enum MyEnum
{
    MyFoo,
    MyBar,
    MyBat
}

MyEnum myEnum = GetMyEnum();
switch (myEnum)
{
    case MyFoo:
        DoFoo();
        break;
    case MyBar:
        DoBar();
        break;
    case MyBat:
        DoBat();
        break;
    default:
        Log("Unexpected value");
        throw new ArgumentException() 
}

Ich glaube nicht, dass dies daran liegt, dass dieser Code niemals erreicht werden kann (selbst bei Unit-Tests). Mein Kollege ist anderer Meinung und glaubt, dass dies uns vor unerwartetem Verhalten schützt, das durch das Hinzufügen neuer Werte zu MyEnum verursacht wird.

Was sagst du, Gemeinde?

sd
quelle
Angenommen, MyEnum ist ein nicht nullwertfähiger Typ.
sd
3
"Heute" ist nicht nullbar. Was ist mit morgen, wenn Sie den Code nicht mehr warten? Oder was ist, wenn "MyBiz" zur Aufzählung hinzugefügt wird, aber nicht der Fall ist? Calebs Kommentare zur Wartung sind sehr wichtig.
1
Bringen Sie Ihrem Compiler bei, dass es sich um einen schwerwiegenden Fehler handelt, wenn ein Schalter nicht alle Fälle abdeckt.
Was MyEnumpassiert, wenn jemand einen ungültigen Wert überträgt, um ihn dann über Ihren Switch weiterzuleiten?
Mawg sagt, Monica
1
Welche Sprache? Wenn Sie Java verwenden, sollten Sie eine Methode in das Enum einfügen und sie einfach aufrufen (Polymorphismus), wodurch die switchAnweisung vollständig entfernt wird.
user949300

Antworten:

34

Das Einbeziehen der Standard-Groß- / Kleinschreibung ändert nichts an der Funktionsweise Ihres Codes, verbessert jedoch die Wartbarkeit Ihres Codes. Indem Sie den Code auf offensichtliche Weise umbrechen lassen (eine Nachricht protokollieren und eine Ausnahme auslösen), fügen Sie dem Praktikanten, den Ihr Unternehmen im nächsten Sommer einstellt, einen großen roten Pfeil hinzu, um einige Funktionen hinzuzufügen. Der Pfeil sagt: "Hey, du! Ja, ich spreche mit DIR! Wenn du der Aufzählung einen weiteren Wert hinzufügen willst, solltest du auch hier einen Fall hinzufügen." Dieser zusätzliche Aufwand kann dem kompilierten Programm einige Bytes hinzufügen, was zu berücksichtigen ist. Aber es rettet auch jemanden (vielleicht sogar Ihre Zukunft) irgendwo zwischen einer Stunde und einem Tag unproduktiven Kopfkratzens.


Update: Die oben beschriebene Situation, dh der Schutz vor Werten, die zu einem späteren Zeitpunkt zu einer Aufzählung hinzugefügt werden, kann auch vom Compiler abgefangen werden. Clang (und meiner Meinung nach gcc) geben standardmäßig eine Warnung aus, wenn Sie einen Aufzählungstyp einschalten, aber keinen Fall haben, der jeden möglichen Wert in der Aufzählung abdeckt. Wenn Sie beispielsweise die defaultGroß- / Kleinschreibung von Ihrem Switch entfernen und MyBazder Aufzählung einen neuen Wert hinzufügen , wird eine Warnung mit folgendem Inhalt angezeigt:

Enumeration value 'MyBaz' not handled in switch

Wenn Sie den Compiler ungedeckte Fälle erkennen lassen, wird die Notwendigkeit für diesen nicht erreichbaren defaultFall, der Ihre Frage überhaupt erst inspiriert hat , weitestgehend beseitigt .

Caleb
quelle
2
Ok, du hast mich überzeugt :) Ich muss nur die Beule in meinen Code-Deckungsnummern akzeptieren.
sd
@st Es gibt keinen Grund, diesen Code nicht zu testen. Führen Sie einfach einen Testbuild durch, der einen zusätzlichen Wert in Ihrer Enumeration bedingt kompiliert, und schreiben Sie dann einen Komponententest, der ihn verwendet. Vielleicht ist das nicht ideal, aber es ist wahrscheinlich nicht der einzige Fall, in dem Sie Code testen müssen, der normalerweise nie erreicht wird.
Caleb
Oder Sie wandeln einen Nicht-Aufzählungswert in Ihren Aufzählungstyp um und verwenden diesen.
Mawg sagt, Monica
5

Ich habe heute Morgen auch gerade mit einem Kollegen darüber gesprochen - es ist wirklich bedauerlich, aber ich denke, dass die Handhabung der Standardeinstellungen aus Sicherheitsgründen erforderlich ist, und zwar aus zwei Gründen:

Erstens, wie Ihr Kollege erwähnt, wird der Code zukunftssicher gegen neue Werte, die der Aufzählung hinzugefügt werden, gemacht. Dies mag wie eine Möglichkeit erscheinen oder auch nicht, aber es ist immer da.

Je nach Sprache / Compiler kann es wichtiger sein, dass Ihre geschaltete Variable Werte enthält, die nicht Mitglieder der Aufzählung sind. Zum Beispiel in C #:

MyEnum myEnum = (MyEnum) 3; // This could come from anywhere, maybe parsed from text?
// ... code goes on for a while

switch ( myEnum )
{
    case MyEnum.A:
        // ... handle A case
        break;
    case MyEnum.B:
        // ... handle B case
        break;
}

// ... code that expects either A or B to have happened

Indem Sie das Einfache hinzufügen case default:und eine Ausnahme auslösen, schützen Sie sich vor diesem seltsamen Fall, in dem "nichts" passiert, aber "etwas" hätte passieren sollen.

Leider ist es so, dass ich jedes Mal, wenn ich eine switch-Anweisung schreibe, die Fälle einer Aufzählung überprüfe. Ich wünschte wirklich, das Verhalten "standardmäßig werfen" könnte durch die Sprache selbst erzwungen werden (zumindest durch Hinzufügen eines Schlüsselworts).

Chris Phillips
quelle
3

Das Hinzufügen eines Standardfalls, auch wenn Sie nie damit rechnen, dass er erreicht wird, kann eine gute Sache sein. Dies erleichtert das Debuggen erheblich, wenn Ihr Code sofort und nicht später im Programm eine Ausnahme "Das hätte nicht passieren dürfen" auslöst, eine mysteriöse Ausnahme auslöst oder unerwartete Ergebnisse ohne Fehler zurückgibt.

Ryathal
quelle
2

Ich sage:

Versuchen Sie, einen anderen Typ hinzuzufügen MyEnum . Dann ändern Sie diese Zeile:

MyEnum myEnum = GetMyEnum();

zu

MyEnum myEnum = SomethingElse;

Führen Sie dann Ihren Code mit dem Standardfall und aus ohne den Standardfall aus. Welches Verhalten bevorzugen Sie?

Der Standardfall kann auch nützlich sein, um NULLWerte abzufangen und zu verhindern NullPointerExceptions.

FrustratedWithFormsDesigner
quelle
-1

Wenn Sie eine Vorstellung davon haben, wie Sie Zeit sparen können, indem Sie auf den Standardfall bestehen, brauchen Sie die Frage nicht zu stellen. Stilles Nichtstun im Fehlerfall ist nicht akzeptabel. Fangen Sie stillschweigend Ausnahmen ab, die niemals auftreten sollten? Das Verlassen von "Minen" für Programmierer, die Ihnen folgen, ist ebenfalls inakzeptabel.

Wenn Ihr Code niemals geändert oder modifiziert wird und zu 100% fehlerfrei ist, ist es möglicherweise in Ordnung, den Standardfall wegzulassen.

Ada (der Großvater der robusten Programmiersprachen) kompiliert keinen Schalter für eine Enumeration, es sei denn, alle Enumationen sind abgedeckt oder es gibt einen Standard-Handler - diese Funktion steht für jede Sprache auf meiner Wunschliste. Unser Ada-Kodierungsstandard besagt, dass bei eingeschalteten Enums die explizite Behandlung aller Werte ohne Vorgabe die bevorzugte Methode ist, um mit dieser Situation umzugehen.

mattnz
quelle
Warum alle -1?
Mattnz
2
Ich habe dich nicht-1, aber ich
denke,