65

我无法弄清楚如何跳出包含 switch 语句的循环。Break 脱离开关,而不是循环。

可能有一个更优雅的解决方案。我已经实现了一个标志,该标志以 true 开头并设置为 false 并结束循环。你能提供更好的解决方案吗?

背景:此代码用于条码工作流系统。我们有内置条形码扫描仪的 PocketPC。此代码用于其中一项功能。它在整个例程中提示用户输入不同的数据。这部分允许他们滚动浏览一些在 PocketPC 终端上显示该信息的库存记录(分页结果),并允许他们输入“D”表示完成,“Q”表示退出。

这是当前需要改进的 C# 示例:

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

谢谢,

4

15 回答 15

53

我会尽量避免它,但你可以使用...

然而,如果你选择这样做,带着干草叉的愤怒暴徒会成为职业危害。

于 2009-12-31T22:56:09.407 回答
50

我发现这种形式更具可读性:

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; 
    } 
}
于 2009-12-31T23:22:58.103 回答
31

这里的一个选择是将此循环重构为一个方法(“提取方法”),并使用return.

于 2009-12-31T22:58:44.837 回答
12

我知道的唯一其他方式是可怕的 goto。 MSDN 也这么说。

但是,我认为您没有理由在这种情况下使用它。您实现的方式运行良好,并且比 goto 更易于维护。我会保留你所拥有的。

于 2009-12-31T22:56:34.227 回答
10

对于多级中断,您必须使用 goto 语句。它似乎是 C# 中唯一的“干净”方式。使用标志也很有用,但如果循环有其他运行困境,则需要额外的代码。

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

有趣的是,其他一些非 c 语言通过执行具有多级中断(不过,Java 也一样没用,因为它使用 goto 伪装成 continue .. :P)break levels;

于 2009-12-31T22:55:21.533 回答
8

为什么不将开关包装到一个返回布尔值以继续循环的方法中?它的附带好处是使代码更具可读性。有人写了一篇论文说我们毕竟不需要 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;
}
于 2009-12-31T23:12:22.017 回答
7

你不能轻易地跳出外循环,但你可以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");
于 2012-08-01T21:53:05.627 回答
4

标志是执行此操作的标准方法。我知道的唯一其他方法是使用goto.

于 2009-12-31T22:55:23.810 回答
2

您可以用switch语句替换if/else语句。不需要gotobreak语句离开循环:

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)
于 2009-12-31T23:13:23.730 回答
1

将其包装成一个函数并使用 return 语句退出。那个怎么样?

于 2009-12-31T23:07:25.793 回答
1

whileIMO,这似乎是打破循环的完美方式。它可以满足您的期望,而且没有副作用。我可以想到做

if(!keepOnLooping)
  break;

但这在执行方面并没有什么不同。

于 2009-12-31T22:57:19.610 回答
1

写一些类似的东西:

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

此中断不会与任何案例相关联。它将属于while循环。

于 2013-10-10T06:08:18.160 回答
0

另一个(不是那么好)的选择是唯一地处理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");

此外,如果由于某种原因将整个事物重构为一个新方法(这是最优雅的解决方案)是不可接受的,那么您也可以依靠匿名委托在现有方法中执行相同的操作。

于 2013-10-15T08:14:54.457 回答
0

您可以将 switch 语句更改为 for/foreach 循环。一旦满足条件,将“keepOnLooping”设置为 false,然后使用 break 退出循环。其余的应该照顾好自己。

于 2009-12-31T23:09:09.333 回答
-2

可能会也可能不会,但是 lamda 为什么不试一试只是为了好玩

while(  (expr) => (){
switch(expr){
case 1: dosomething; return true; 
case 2 : something;return true;
case exitloop:return false;}
});   
于 2017-08-23T21:53:34.767 回答