web-dev-qa-db-fra.com

Éteindre une boucle while contenant une instruction switch

Je ne parviens pas à comprendre comment sortir d'une boucle contenant une instruction switch. Break se déclenche hors du commutateur, pas de la boucle.

Il existe probablement une solution plus élégante à cela. J'ai implémenté un drapeau qui commence comme étant vrai et se met à faux et termine la boucle. Pouvez-vous offrir une meilleure solution?

Contexte: ce code est utilisé dans un système de flux de travail de code à barres. Nous avons des PocketPC dotés de scanneurs de code à barres intégrés. Ce code est utilisé dans l’une de ces fonctions. Il invite l'utilisateur à entrer différentes données tout au long de la routine. Cette pièce leur permet de faire défiler des enregistrements d'inventaire affichant ces informations sur le terminal PocketPC (résultats paginés) et leur permet d'entrer «D» pour Terminé, «Q» pour quitter.

Voici l'exemple actuel de C # qui doit être amélioré:

do
{
    switch (MLTWatcherTCPIP.Get().ToUpper())
    {
        case "": //scroll/display next inventory location
            MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextDown();
            break;
        case "P": //scroll/display previous inventory location
            MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextDown();
            break;
        case "D": //DONE (exit out of this Do Loop)
            // break; // this breaks out of the switch, not the loop
            // return; // this exists entire method; not what I'm after
            keepOnLooping = false;
            break;
        case "Q": //QUIT (exit out to main menu)
            return;
        default:
            break;
    }
} while (keepOnLooping);

Voici un exemple de code qui fait cela dans VB.NET

Do
    Select Case MLTWatcherTCPIP.Get().ToUpper
        Case "" ''#scroll/display next inventory location
            MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextDown()
        Case "P" ''#scroll/display previous inventory location
            MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextUp()
        Case "D" ''#DONE (exit out of this Do Loop)
            Exit Do
        Case "Q" ''#QUIT (exit out to main menu)
            Return
    End Select
Loop

Merci,

45
joshblair

Je trouve ce formulaire plus lisible que jamais:

bool done = false;
while (!done) 
{ 
    switch (MLTWatcherTCPIP.Get().ToUpper()) 
    { 
        case "": //scroll/display next inventory location 
            MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextDown(); 
            break; 
        case "P": //scroll/display previous inventory location 
            MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextDown(); 
            break; 
        case "D": //DONE (exit out of this Do Loop) 
            done = true;
            break; 
        case "Q": //QUIT (exit out to main menu) 
            return; 
        default: 
            break; 
    } 
}
37
Jeffrey L Whitledge

J'essaierais de l'éviter, mais tu pourrais utiliser ...

 

aller à

Cependant, les foules en colère avec des fourches deviennent un risque professionnel si vous choisissez de le faire.

43
Kevin Montrose

Une option consiste à refactoriser cette boucle dans une méthode ("extraire la méthode") et à utiliser return

29
Marc Gravell

Le seul autre moyen que je connaisse est le goto redouté. MSDN dit aussi ceci.

Cependant, je ne vois aucune raison pour laquelle vous l'utiliseriez dans ce cas. La manière dont vous avez implémenté fonctionne bien et est plus facile à gérer qu'un goto. Je garderais ce que tu as.

12
McAden

Vous devez utiliser une instruction goto pour les pauses à plusieurs niveaux. Il semble que ce soit la seule manière «propre» en C #. L'utilisation d'un indicateur est également utile, mais requiert du code supplémentaire si la boucle a d'autres prédicats à exécuter.

http://msdn.Microsoft.com/en-us/library/aa664756(VS.71).aspx

Il peut être intéressant de noter que certains autres langages non-c ont des ruptures sur plusieurs niveaux en faisant break levels; (Java est tout aussi inutile, car il utilise un goto déguisé en continu ...: P)

10
Tor Valamo

Pourquoi ne pas envelopper le commutateur dans une méthode qui renvoie un booléen pour continuer à boucler? Cela aurait l'avantage de rendre le code plus lisible. Il y a une raison pour laquelle quelqu'un a écrit un papier en disant que nous n'avons pas besoin de déclarations goto après tout;) 

do
{
    bool keepOnLooping = TryToKeepLooping();
} while (keepOnLooping);

private bool TryToKeepLooping()
{
    switch (MLTWatcherTCPIP.Get().ToUpper())
    {
        case "": //scroll/display next inventory location
            MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextDown();
            break;
        case "P": //scroll/display previous inventory location
            MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextDown();
            break;
        case "D": //DONE (exit out of this Do Loop)
            // break; // this breaks out of the switch, not the loop
            // return; // this exists entire method; not what I'm after
            return false;
        case "Q": //QUIT (exit out to main menu)
            return true;
        default:
            break;
    }

    return true;
}
8
Jeffrey Cameron

Vous ne pouvez pas facilement sortir de la boucle externe, mais vous pouvez continue le.

Si vous inversez votre logique, alors vous obtenez ceci. Notez qu’il existe un break immédiatement après l’instruction switch pour quitter la boucle.

Ce n'est pas un code très lisible à mon avis et je pense qu'un drapeau est toujours le meilleur.

   do
         {
            switch (Console.ReadKey().KeyChar.ToString())
            {
                case "U":
                    Console.WriteLine("Scrolling up");
                    continue;

                case "J":
                    Console.WriteLine("Scrolling down");
                    continue;

                case "D": //DONE (exit out of this Do Loop)
                    break;

                case "Q": //QUIT (exit out to main menu)
                    return;

                default:
                    Console.WriteLine("Continuing");
                    continue;
            }

            break;

        } while (true);

        Console.WriteLine("Exited");
4
Simon_Weaver

Un drapeau est le moyen standard de le faire. Le seul autre moyen que je connaisse est d'utiliser un goto

4
John Knoeller

Vous pouvez remplacer l'instruction switch par une instruction if/else. Non goto nécessaire et l'instruction break laisse la boucle:

do
{
  String c = MLTWatcherTCPIP.Get().ToUpper();

  if (c = "")
    MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextDown();
  else if (c = "P")
    MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextUp();
  else if (c = "D")
     break;
  else if (c = "Q")
    return;
  else
  {
    // Handle bad input here.
  }
} while (keepLooping)
2
Chris R. Timmons

OMI, cela semble être un excellent moyen de sortir d’une boucle while. Il fait ce que vous attendez sans effets secondaires. Je pourrais penser à faire

if(!keepOnLooping)
  break;

Mais ce n'est pas vraiment différent en termes d'exécution.

1
Fry

Enveloppez-le dans une fonction et utilisez une instruction return pour quitter. Comment sur cela?

1
Hamish Grubijan

Ecrire quelque chose comme:

case "Exit/Break" :
                  //Task to do
                    if(true)
                      break;

Cette pause ne sera associée à aucun cas. Il appartiendra à la boucle while.

1
prashant chaudhary

Vous pouvez changer l’instruction switch en une boucle for/foreach. Une fois la condition remplie, définissez "keepOnLooping" sur false, puis utilisez break pour sortir de la boucle. Le reste devrait prendre soin de lui-même.

0
Chuck Conway

Une autre alternative (pas si géniale) consiste à gérer uniquement la case où vous devez "sortir de la boucle" immédiatement avec une if et la sortir du bloc switch. Pas terriblement élégant si le boîtier est très long:

do
{
    var expression = MLTWatcherTCPIP.Get().ToUpper();
    if (expression = "D") //DONE (exit out of this Do Loop)
    {   
        statement;
        break;
    }

    switch (expression)
    {
        case "": //scroll/display next inventory location
            MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextDown();
            break;
        case "P": //scroll/display previous inventory location
            MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextDown();
            break;
        case "Q": //QUIT (exit out to main menu)
            return;
        default:
            break;
    }
} while (true); //or whatever your condition is

Vous pouvez également faire de la variable case elle-même une partie de la condition de la boucle while en considérant qu'il vous suffit de sortir de la boucle et que le calcul de l'expression elle-même est trivial (comme pour la lecture d'une variable).

do
{
    switch (expression)
    {
        case "": //scroll/display next inventory location
            MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextDown();
            break;
        case "P": //scroll/display previous inventory location
            MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextDown();
            break;
        case "Q": //QUIT (exit out to main menu)
            return;
        default:
            break;
    }
} while (condition && expression != "D");

De plus, si refactoriser le tout dans une nouvelle méthode (ce qui est la solution la plus élégante) est inacceptable pour une raison quelconque, vous pouvez également compter sur un délégué anonyme pour faire la même chose dans la méthode existante.

0
nawfal