c# - quedar - Salir de un bucle while que contiene una instrucción switch
switch en c# ejercicios (15)
Estoy teniendo problemas para descubrir cómo salir de un bucle que contiene una instrucción switch. Saltos de rotura del interruptor, no el bucle.
Probablemente hay una solución más elegante a esto. He implementado un indicador que comienza como verdadero y se establece en falso y finaliza el bucle. ¿Puedes ofrecer una mejor solución?
Fondo: este código se utiliza en un sistema de flujo de trabajo de código de barras. Tenemos PocketPC que tienen escáneres de códigos de barras integrados. Este código se usa en una de esas funciones. Solicita al usuario diferentes datos a lo largo de la rutina. Esta pieza les permite desplazarse por algunos registros de inventario que muestran esa información en el terminal PocketPC (resultados paginados) y les permite ingresar "D" para Listo, "Q" para salir.
Aquí está el ejemplo actual de C # que necesita ser mejorado:
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);
Aquí hay un ejemplo de código que hace esto en 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
Gracias,
¿Por qué no envolver el conmutador en un método que devuelve un booleano para seguir en bucle? Tendría el beneficio adicional de hacer que el código sea más legible. Hay una razón por la que alguien escribió un artículo diciendo que no necesitamos declaraciones goto después de todo;)
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;
}
Debe utilizar una instrucción goto para los saltos de múltiples niveles. Parece ser la única forma "limpia" en C #. El uso de una bandera también es útil, pero requiere código adicional si el bucle tiene otros problemas para ejecutar.
http://msdn.microsoft.com/en-us/library/aa664756(VS.71).aspx
Puede ser interesante notar que algunos otros lenguajes que no son c tienen saltos de niveles múltiples al hacer break levels ;
(Java es igual de inútil, sin embargo, ya que utiliza un goto disfrazado de continuar ...: P)
En mi opinión, esta parece ser una forma perfecta de salir de un bucle while. Hace lo que esperas sin efectos secundarios. Podría pensar en hacer
if(!keepOnLooping)
break;
Pero eso no es realmente diferente en términos de ejecución.
Envuélvalo en una función y use una declaración de retorno para salir. ¿Qué hay sobre eso?
Escribe algo como:
case "Exit/Break" :
//Task to do
if(true)
break;
Esta ruptura no estará asociada a ningún caso. Pertenecerá al bucle while.
Intentaría evitarlo, pero podrías usar ...
ir
Sin embargo, las turbas enojadas con horcas se convierten en un riesgo laboral si decide hacerlo.
La única otra manera que conozco es el temido goto. MSDN también dice esto.
Sin embargo, no veo ninguna razón por la que lo usarías en este caso. La forma en que has implementado funciona bien y es más fácil de mantener que un goto. Yo mantendría lo que tienes.
Me parece que esta forma es un poco más legible:
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;
}
}
No puede salir fácilmente del bucle externo, pero puede continue
.
Si inviertes tu lógica entonces obtienes esto. Tenga en cuenta que hay una break
inmediatamente después de la instrucción de cambio para salir del bucle.
Este no es un código muy legible en mi opinión, y creo que una bandera sigue siendo la mejor.
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");
Otra alternativa (no tan buena) es manejar de forma única el case
en el que tiene que "salir del bucle" con un " if
inmediato y retirarlo del bloque de switch
. No terriblemente elegante si el interruptor es muy largo:
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
También puede hacer que el case
sea parte de la condición del bucle while, ya que solo tiene que salir del bucle y el cómputo de la expresión en sí es trivial (como leer una 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");
Además, si por alguna razón no se puede refactorizar todo en un nuevo método (que es la solución más elegante), también puede confiar en que un delegado anónimo haga lo mismo dentro del método existente.
Podría cambiar la instrucción de cambio a un bucle for / foreach. Una vez que se cumple la condición, establezca "keepOnLooping" en falso y luego use break para salir del bucle. El resto debe cuidar de sí mismo.
Puede o no funcionar, pero lamda, ¿por qué no darle una oportunidad solo por diversión?
while( (expr) => (){
switch(expr){
case 1: dosomething; return true;
case 2 : something;return true;
case exitloop:return false;}
});
Puede reemplazar la instrucción switch
con una instrucción if/else
. No se necesita goto
y la sentencia break
deja el bucle:
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)
Una bandera es la forma estándar de hacer esto. La única otra forma que conozco es usar un goto
.
Una opción aquí es refactorizar este bucle en un método ("método de extracción"), y usar el return
.