web-dev-qa-db-fra.com

Utilisez un 'goto' dans un commutateur?

J'ai vu une norme de codage suggérée qui se lit Never use goto unless in a switch statement fall-through.

Je ne suis pas À quoi ressemblerait exactement ce cas 'd'exception', qui justifie une goto?

43
Brent Arias

Cette construction est illégale en C #:

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

En C++, il exécuterait les deux lignes si variable = 2. C'est peut-être intentionnel, mais il est trop facile d'oublier break; à la fin de la première étiquette de cas. Pour cette raison, ils l'ont rendu illégal en C #. Pour imiter ce comportement, vous devez utiliser explicitement goto pour exprimer votre intention:

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

Cela dit, il y a quelques casgoto est en fait une bonne solution au problème. Ne ferme jamais ton cerveau avec les règles "ne jamais utiliser quelque chose". Si c'était inutile à 100%, cela n'aurait pas existé dans la langue. Ne pas utiliser goto est un guideline; ce n'est pas une loi.

88
Mehrdad Afshari

C # refuse de laisser les cas tomber implicitement (sauf s'il n'y a pas de code dans le cas) comme en C++: vous avez besoin d'inclure break. Pour explicitement tomber à travers (ou pour sauter à un autre cas), vous pouvez utiliser goto case. Comme il n’ya pas d’autre moyen d’obtenir ce comportement, la plupart des normes de codage (sensées) le permettront.

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;
}

Un exemple réaliste (sur demande):

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
    }

C'est mieux 

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

Que cela (surtout si vous travaillez plus dans Quit ())

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

C’est la seule façon pour le C # d’autoriser un basculement de boîtier de commutateur. En C # (contrairement à C, C++ ou Java), un bloc de casse dans une instruction switch doit se terminer par un break ou une autre instruction de saut explicite.

4
Michael Burr

En plus d'utiliser goto case, vous pouvez goto une étiquette figurant dans une autre clause case:

    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;
    }

De cette façon, vous pouvez passer à une autre clause case sans vous soucier de la valeur ou du type de l'expression.

Une sorte de mot clé "fallthrough" explicite pouvant être remplacé par break aurait été agréable, bien que ...

4
Robert T. Adams

En guise de prolongement du conseil de Mehrdad Afshari ci-dessus, je ne préconiserais jamais d'exiler simplement une construction en tant que "mauvais code" ou "mauvaise pratique de codage". Même les déclarations «goto» ont leur place dans le grand schéma des choses. Le dogme selon lequel ils sont pervers ne s'est pas concrétisé en raison d'un défaut inhérent à la construction - c'était parce qu'ils étaient lourdement (et mal) surexploités.

Dans tous les cas, Kernighan et Ritchie ont estimé qu'il était judicieux de laisser tomber une affaire. Franchement, je suis plus enclin à faire confiance à leur raisonnement qu'à tout ce qui pourrait éventuellement sortir de l'esprit de tout Redmond, dans l'État de Washington. Ou n'importe quel dogme qui repose sur la sagesse de n'importe quel esprit chez Redmond.

Si vous entendez «Ne jamais utiliser xxx», ajoutez-le mentalement avec «sans cause». Jeter quoi que ce soit de manière dogmatique est ridicule. Les appareils existent parce qu'il y avait une raison pour les fabriquer. Avec le recul, ils sont généralement qualifiés de «mauvais», non pas à cause d’une faute de l’appareil lui-même, mais plutôt parce qu’ils étaient mal employés par des personnes qui ne les comprenaient pas complètement. Ainsi, l'appareil n'est presque jamais «mauvais». Ce qui est presque toujours mauvais, c'est l'utilisateur la compréhension . Cela est vrai même de la fission et de la fusion atomiques.

J'ai vu des structures de code horriblement grotesques dont la seule fonction était d'éviter l'utilisation d'une instruction 'goto'. Quel est le pire? "goto [label]", ou 30 lignes de code dégoûtant dont la fonction est d'éviter d'avoir à taper "goto [label]"?

Chercher la connaissance avant le dogme. Pense avant d'agir. Ce sont des conseils utiles.

1
David Wright