Sortir d'une boucle while qui contient une instruction switch
-
22-09-2019 - |
Question
Je ne parviens pas à trouver comment sortir d'une boucle qui contient une instruction switch. Briser les pauses de l'interrupteur, et non la boucle.
Il y a probablement une solution plus élégante à ce sujet. Je l'ai mis en place un drapeau qui commence comme vrai et obtient la valeur false et la boucle se termine. Pouvez-vous offrir une meilleure solution?
Arrière-plan: ce code est utilisé dans un système de workflow de codes à barres. Nous avons PocketPC qui ont des scanners de codes à barres intégrés. Ce code est utilisé dans l'une de ces fonctions. Il invite l'utilisateur à différentes données tout au long de la routine. Cette pièce leur permet de faire défiler des enregistrements d'inventaire indiquant que les informations sur le terminal PocketPC (paginés résultats) et leur permet d'entrer dans « D » pour DONE, « 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,
La solution
Je trouve cette forme d'être toujours aussi un peu plus lisible:
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;
}
}
Autres conseils
Je vais essayer de l'éviter, mais vous pouvez utiliser ...
goto
Cependant, des foules en colère à coups de fourche devenir un risque professionnel si vous choisissez de le faire.
Une option ici est de factoriser cette boucle dans une méthode ( « méthode d'extraction ») et utiliser return
.
La seule autre façon que je connaisse est le goto redoutée. MSDN dit aussi cela.
Cependant, je ne vois aucune raison pour laquelle vous souhaitez utiliser dans ce cas. La façon dont vous avez mis en œuvre fonctionne très bien, et est plus maintenable qu'un goto. Je garderais ce que vous avez.
Vous devez utiliser une instruction goto pour les pauses à plusieurs niveaux. Il semble être la seule façon « propre » en C #. L'utilisation d'un drapeau est également utile, mais nécessite un code supplémentaire si la boucle a d'autres situations difficiles pour la course.
http://msdn.microsoft.com/en -us / bibliothèque / aa664756 (VS.71) .aspx
Il peut être intéressant de noter que certaines autres langues non c ont des pauses multi-niveaux en faisant break levels;
(Java est tout aussi inutile, cependant, car il utilise un goto déguisé en continue ..: P)
Pourquoi ne pas envelopper l'interrupteur dans une méthode qui retourne un booléen pour maintenir le bouclage? Il aurait l'avantage secondaire de rendre le code plus lisible. Il y a une raison que quelqu'un a écrit un article disant que nous ne avons pas besoin des 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;
}
Un drapeau est le moyen standard pour le faire. La seule autre façon que je connaisse est d'utiliser un goto
.
Vous ne pouvez facilement sortir de la boucle extérieure, mais vous pouvez continue
il.
Si vous inversez alors votre logique vous obtenez ceci.
Notez qu'il est un break
immédiatement après l'instruction de commutation pour sortir de la boucle.
Ce n'est pas un code très lisible à mon avis, et je pense que le drapeau est toujours préférable.
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");
Vous pouvez remplacer l'instruction switch
avec une déclaration if/else
. Aucune goto
nécessaire et l'instruction break
quitte 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)
Enveloppez dans une fonction et utiliser une instruction de retour pour quitter. Que diriez-vous cela?
OMI, cela semble une façon parfaitement bien de sortir d'une boucle de while
. Il fait ce que vous attendez sans effets secondaires. Je pouvais penser à faire
if(!keepOnLooping)
break;
Mais ce n'est pas vraiment différent en termes d'exécution.
Ecrire quelque chose comme:
case "Exit/Break" :
//Task to do
if(true)
break;
Cette rupture ne sera pas associé à tous les cas. Il appartiendra à la boucle while
.
Vous pouvez modifier l'instruction de passer à une boucle pour / foreach. Une fois que la condition est remplie set « keepOnLooping » false puis utilisez pause pour sortir de la boucle. Le reste devrait prendre soin de lui-même.
Une autre (pas grand) alternative consiste à gérer de façon unique le case
où vous devez « sortir de la boucle » avec un if
de suite et le déplacer hors du bloc de switch
. Pas très élégant si l'interrupteur cas est très longue:
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 le case
lui-même une partie de la condition de la boucle de while
vous envisagez suffit de sortir de la boucle et le calcul de l'expression elle-même est trivial (comme 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");
Aussi, si refactoring la chose entière dans une nouvelle méthode (qui est la solution la plus élégante à ce) 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.
ou non fonctionner, mais lamda pourquoi ne pas donner un coup de feu juste pour le fun
while( (expr) => (){
switch(expr){
case 1: dosomething; return true;
case 2 : something;return true;
case exitloop:return false;}
});