Выйти из цикла while, содержащего оператор switch - программирование
Подтвердить что ты не робот

Выйти из цикла while, содержащего оператор switch

Мне трудно понять, как выйти из цикла, содержащего оператор switch. Разрыв выходит из переключателя, а не из цикла.

Возможно, это более элегантное решение. Я реализовал флаг, который начинается как истинный и получает значение false и завершает цикл. Можете ли вы предложить лучшее решение?

Фон: этот код используется в системе документооборота штрих-кода. У нас есть карманные компьютеры, в которых встроены сканеры штрих-кода. Этот код используется в одной из этих функций. Он запрашивает у пользователя разные данные во время процедуры. Эта часть позволяет им прокручивать некоторые записи инвентаря, отображающие эту информацию на терминале PocketPC (выгружаемые результаты) и позволяет им вводить "D" для "Готово", "Q", чтобы выйти.

Вот текущий пример С#, который необходимо улучшить:

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

Вот пример кода, который делает это в 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

Спасибо,

4b9b3361

Ответ 1

Я считаю, что эта форма становится все более читаемой:

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

Ответ 2

Я попытался бы избежать этого, но вы могли бы использовать...

goto

Тем не менее, сердитые мобы с вилами становятся профессиональной опасностью, если вы решите это сделать.

Ответ 3

Один из вариантов заключается в том, чтобы реорганизовать этот цикл в метод (метод "extract" ) и использовать return.

Ответ 4

Единственный другой способ, о котором я знаю, - это страшный goto. MSDN также говорит об этом.

Однако я не вижу причин, по которым вы бы использовали его в этом случае. То, как вы реализовали, отлично работает, и является более удобным, чем goto. Я бы сохранил то, что у вас есть.

Ответ 5

Вы должны использовать инструкцию goto для многоуровневых разрывов. Кажется, это единственный "чистый" способ в С#. Использование флага также полезно, но требует дополнительного кода, если у цикла есть другие трудности при запуске.

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

Интересно отметить, что некоторые другие языки не-c имеют разрывы на разных уровнях, делая break levels; (Java так же бесполезен, хотя, поскольку он использует goto, замаскированный как продолжение..: P)

Ответ 6

Почему бы не включить коммутатор в метод, который возвращает логическое значение для продолжения цикла? Было бы полезно получить код более удобочитаемым. Там причина, по которой кто-то написал статью, в которой говорится, что нам не нужны инструкции goto в конце концов;)

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

Ответ 7

Флаг - стандартный способ сделать это. Единственный другой способ, которым я знаю, - использовать goto.

Ответ 8

Вы не можете легко выйти из внешнего цикла, но вы можете continue его.

Если вы измените свою логику, вы получите это. Обратите внимание, что после завершения операции switch оператор break должен выйти из цикла.

Это не очень читаемый код, на мой взгляд, и я считаю, что флаг все же лучше всего.

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

Ответ 9

Вы можете заменить оператор switch оператором if/else. Нет goto, а инструкция break оставляет цикл:

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)

Ответ 10

IMO, это кажется прекрасным способом выхода из цикла while. Он делает то, что вы ожидаете, без побочных эффектов. Я мог подумать о том, чтобы делать

if(!keepOnLooping)
  break;

Но это не совсем другое в плане исполнения.

Ответ 11

Вставьте его в функцию и используйте оператор return для выхода. Как насчет этого?

Ответ 12

Напишите что-то вроде:

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

Этот разрыв не будет связан ни с одним случаем. Он будет принадлежать циклу while.

Ответ 13

Вы можете изменить оператор switch в цикле for/foreach. После выполнения условия установите "keepOnLooping" в значение false, а затем используйте break, чтобы выйти из цикла. Остальное должно позаботиться о себе.

Ответ 14

Другая (не такая уж большая) альтернатива - это однозначно обрабатывать case, где вам нужно "вырваться из цикла" с помощью if сразу и вывести его из блока switch. Не очень элегантно, если коммутатор очень длинный:

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

Вы также можете сделать case частью условия цикла while, считая, что вам нужно выйти из цикла, а вычисление самого выражения тривиально (например, чтение переменной).

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

Также, если по какой-то причине рефакторинг всей вещи в новый метод (который является самым изящным решением для этого) неприемлем, тогда вы также можете полагаться на анонимный делегат, чтобы сделать то же самое внутри существующего метода.

Ответ 15

Может или может не работать, но ламда, почему бы не дать ему выстрел просто для удовольствия.

while(  (expr) => (){
switch(expr){
case 1: dosomething; return true; 
case 2 : something;return true;
case exitloop:return false;}
});