it-swarm.com.de

Verwenden Sie einen "goto" in einem Schalter?

Ich habe einen vorgeschlagenen Kodierungsstandard gesehen, der Never use goto unless in a switch statement fall-through liest.

Ich folge nicht Wie genau würde dieser Ausnahmefall aussehen, der eine goto rechtfertigt?

43
Brent Arias

Dieses Konstrukt ist in C # ungültig:

switch (variable) {
   case 2: 
       Console.WriteLine("variable is >= 2");
   case 1:
       Console.WriteLine("variable is >= 1");
}

In C++ würden beide Zeilen ausgeführt, wenn variable = 2. Es kann beabsichtigt sein, aber es ist zu leicht, break; am Ende des ersten Falletiketts zu vergessen. Aus diesem Grund haben sie es in C # illegal gemacht. Um das Durchfallverhalten nachzuahmen, müssen Sie explizit goto verwenden, um Ihre Absicht auszudrücken:

switch (variable) {
   case 2: 
       Console.WriteLine("variable is >= 2");
       goto case 1;
   case 1:
       Console.WriteLine("variable is >= 1");
       break;
}

Das heißt, es gibt einige Fälle , bei denen goto tatsächlich eine gute Lösung für das Problem ist. Niemals dein Gehirn herunterfahren mit den Regeln "Nimm niemals etwas". Wenn es zu 100% nutzlos wäre, hätte es die Sprache überhaupt nicht gegeben. Verwenden Sie nicht goto eine guideline; Es ist kein Gesetz.

88
Mehrdad Afshari

C # weigert sich, Fälle wie in C++ implizit durchzulassen (es sei denn, es gibt keinen Code): Sie müssen, um break einzuschließen. Um explizit durchzufallen (oder um zu einem anderen Fall zu springen) können Sie goto case verwenden. Da es keine andere Möglichkeit gibt, dieses Verhalten zu erhalten, werden die meisten (sinnvollen) Kodierungsstandards dies ermöglichen.

switch(variable)
{
case 1:
case 2:
    // do something for 1 and 2
    goto case 3;
case 3:
case 4:
    // do something for 1, 2, 3 and 4
    break;
}

Ein realistisches Beispiel (auf Anfrage):

switch(typeOfPathName)
{
case "relative":
    pathName = Path.Combine(currentPath, pathName);
    goto case "absolute";

case "expand":
    pathName = Environment.ExpandEnvironmentVariables(pathName);
    goto case "absolute";

case "absolute":
    using (var file = new FileStream(pathName))
    { ... }
    break;

case "registry":
    ...
    break;
}
21
Zooba
   public enum ExitAction {
        Cancel,
        LogAndExit,
        Exit
    }

Das ist ordentlich 

ExitAction action = ExitAction.LogAndExit;
switch (action) {
    case ExitAction.Cancel:
        break;
    case ExitAction.LogAndExit:
        Log("Exiting");
        goto case ExitAction.Exit;
    case ExitAction.Exit:
        Quit();
        break;
}

Dann (besonders wenn Sie mehr Arbeit in Quit () erledigen)

ExitAction action = ExitAction.LogAndExit;
switch (action) {
    case ExitAction.Cancel:
        break;
    case ExitAction.LogAndExit:
        Log("Exiting");
        Quit();
        break;
    case ExitAction.Exit:
        Quit();
        break;
}
7
djeeg

Es ist die einzige Möglichkeit, dass C # ein "Fallthrough" eines Switch-Gehäuses zulässt. In C # (im Gegensatz zu C, C++ oder Java) muss ein Case-Block in einer switch-Anweisung mit einer break oder einer anderen expliziten Sprunganweisung enden.

4
Michael Burr

Zusätzlich zu goto case können Sie goto eine Beschriftung verwenden, die sich in einer anderen Case-Klausel befindet:

    switch(i) {
    case "0":
        // do some stuff
        break;
    case "1":
        // other stuff, then "fall through" to next case clause
        goto Case2;
    case "2":
    Case2:
        break;
    }

Auf diese Weise können Sie zu einer anderen case-Klausel springen, ohne sich um den Wert oder den Typ des Ausdrucks zu kümmern.

Eine Art explizites "Fallthrough" - Schlüsselwort, das break ersetzt werden kann, wäre jedoch Nizza gewesen ...

4
Robert T. Adams

Als Erweiterung des obigen Rates von Mehrdad Afshari würde ich niemals dafür plädieren, ein Konstrukt einfach als "schlechten Code" oder "schlechte Kodierungspraxis" zu verbannen. Sogar "goto" -Statements haben ihren Platz im großen Schema der Dinge. Das Dogma, dass sie böse sind, wurde aufgrund eines inhärenten Fehlers des Konstrukts nicht erfüllt - es lag daran, dass sie stark (und schlecht) überstrapaziert wurden.

In jedem Fall waren Kernighan und Ritchie der Ansicht, dass das Durchlassen eines Falles der richtige Weg ist. Ehrlich gesagt bin ich eher geneigt, ihrer Argumentation zu vertrauen als irgendetwas, das in ganz Redmond, Washington, denkbar wäre. Oder jedes Dogma, das auf der Weisheit eines Geistes in Redmond beruht.

Wenn Sie jemals "Niemals xxx verwenden" hören, hängen Sie das mit "ohne Grund" an. Etwas dogmatisch zu werfen, ist lächerlich. Geräte existieren, weil es einen Grund gab, sie herzustellen. Sie werden im Nachhinein normalerweise als "schlecht" bezeichnet, nicht wegen eines Fehlers am Gerät selbst, sondern eher weil sie von Personen, die sie nicht vollständig verstanden haben, schlecht eingestellt waren. Daher ist das Gerät kaum "schlecht". Was fast immer schlecht ist, ist Benutzer Verständnis. Dies gilt sogar für die Atomspaltung und -fusion.

Ich habe schrecklich groteske Codestrukturen gesehen, deren einzige Funktion darin bestand, die Verwendung einer 'goto'-Anweisung zu vermeiden. Was ist schlimmer "goto [label]" oder 30 Zeilen ekelhaften Codes, dessen Funktion darin besteht, zu vermeiden, dass "goto [label]" eingegeben werden muss?

Sucht Wissen vor dem Dogma. Denk nach bevor du handelst. Dies sind nützliche Ratschläge.

1
David Wright