Salir de un ciclo while que contiene una instrucción switch

Tengo problemas para descubrir cómo salir de un bucle que contiene una statement de cambio. La pausa se rompe del interruptor, no del lazo.

Probablemente haya una solución más elegante para esto. Implementé una bandera que comienza como verdadera y se establece en falsa y finaliza el ciclo. ¿Puedes ofrecer una mejor solución?

Antecedentes: este código se usa en un sistema de flujo de trabajo de código de barras. Tenemos PocketPCs con escáneres de código 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 de PocketPC (resultados paginados) y les permite ingresar “D” para Hecho, “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,

Encuentro que esta forma es cada vez más fácil de leer:

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

Trataría de evitarlo, pero podrías usar …

ir

Sin embargo, las mobs enojadas con horcas se convierten en un riesgo laboral si decides hacerlo.

Una opción aquí es refactorizar este ciclo en un método (“método de extracción”), y usar return .

La única otra forma 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 ha implementado funciona bien, y es más fácil de mantener que un goto. Mantendré lo que tienes.

Debe usar una statement goto para pausas de niveles múltiples. Parece ser la única forma “limpia” en C #. Usar una bandera también es útil, pero requiere código adicional si el ciclo tiene otras situaciones difíciles para ejecutar.

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

Puede ser interesante observar que algunos otros lenguajes no c tienen saltos de varios niveles al hacer los break levels ; (Java es igualmente inútil, ya que utiliza un goto disfrazado como un continuo …: P)

¿Por qué no ajustar el interruptor en un método que devuelve un valor 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; } 

Una bandera es la forma estándar de hacer esto. La única otra forma que conozco es usar un goto .

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 statement de cambio para salir del bucle.

Este código no es muy legible en mi opinión, y creo que una bandera es aún 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"); 

Puede reemplazar la instrucción switch por una instrucción if/else . No es necesario goto y la statement de break sale del ciclo:

 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) 

Envuélvalo en una función y use una statement de retorno para salir. ¿Qué hay sobre eso?

OMI, esta parece una excelente manera de salir de un ciclo 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.

Escribe algo como:

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

Este descanso no se asociará con ningún caso. Pertenecerá al ciclo while.

Puede cambiar la instrucción switch a un ciclo for / foreach. Una vez que se cumple la condición, configure “keepOnLooping” en false y luego use break para salir del ciclo. El rest debería cuidarse solo.

Otra alternativa (no tan buena) es manejar de forma única el case en el que tiene que “salirse del lazo” con un if inmediatamente y sacarlo del bloque de switch . No es terriblemente elegante si la caja del interruptor es muy larga:

 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 mismo sea una parte de la condición de while loop ya que solo tiene que salir del ciclo y el cálculo 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 refactorizar todo el asunto en un nuevo método (que es la solución más elegante para esto) es inaceptable por alguna razón, entonces también puede confiar en un delegado anónimo para hacer lo mismo dentro del método existente.

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