【问题标题】:break enclosing switch statement from inner for loop?从内部for循环中断封闭的switch语句?
【发布时间】:2012-07-05 17:26:50
【问题描述】:

考虑以下 C#:

// C# .net
switch(x)
   {
    case 1:
        for(int i = 0; i < 10; i++)
        {
            int val = getValue(i);
            if (val == 0)
                goto endswitch;
        }
        doMoreStuff();
        break;
    case 2:
        doSomeThingElse();
        break;
    default: throw new ArgumentOutOfRangeException();
}
endswitch: ;

我已经编写了类似于上述代码示例的代码。问题是我需要从内部 for 循环内部中断 switch 语句。如果我在那里放一个break 语句,它只会打破内部for 循环,然后继续doMoreStuff(),这不是我需要的。

这里似乎效果最好的替代方法是goto 声明,但我知道这不受欢迎。

另一种选择是在 for 循环中跟踪一个单独的变量,但这会增加代码行并且不太优雅。

最好的方法是什么?

更新: 我读到有一种方法可以在 JavaScript 中执行此操作。它的工作原理是这样的:(http://www.devguru.com/technologies/ecmascript/quickref/break.html)

// JavaScript
outer_loop:
for(i=0; i<3; i++)
{
   document.write("<BR>" + "outer " + i + ":   ");
   for(j=0; j<5; j++)
   {
      document.write("inner " + j + " ");
      if(j==x)
         break outer_loop;
   }
}

这样的事情在 C# 中可能吗?

【问题讨论】:

  • valbool 还是 int?您的代码不会按原样编译。
  • 由于缺少括号“{”,代码无法编译。一定是用户打错了。
  • 从代码中也可以看出 val x 是一个整数。
  • 如果合适,考虑用多态性替换switch 语句。请参阅“[告诉,不要问]”原则 (pragprog.com/articles/tell-dont-ask)。

标签: c# .net controls structure goto


【解决方案1】:

您可以将检查抽象为带有返回标志的方法:

switch(x)
{
    case 1:
        if (ShouldDoMoreStuff())
            doMoreStuff();
        break;
    case 2:
        doSomeThingElse();
        break;
    default: throw new ArgumentOutOfRangeException();
}


private bool ShouldDoMoreStuff()
{
    for(int i = 0; i < 10; i++)
    {
        var val = getValue(i);
        if (val == 0)
            return false;
    }

    return true;
}

只是为了扩展,您可以像以前一样使用 goto,但它通常不受欢迎,尤其是在这种微不足道的情况下。 有时当你有很多很多嵌套循环或开关时它很有用,但这通常表明你应该重构/重新设计一下。正如您所指出的,您可以存储一个局部变量并进行检查,但正如您所意识到的那样,这有点迟钝/难闻。我更喜欢我在上面发布的这种方法,因为它变得非常易读。

编辑:关于您的评论和编辑的问题,我认为 C# 中不存在与您的 JavaScript 代码类似的语言功能。来自http://msdn.microsoft.com/en-us/library/37zc9d2w%28VS.80%29.aspx(强调):

在嵌套语句中,break 语句仅终止 do, 立即将其括起来的 for、switch 或 while 语句。你可以 使用 return 或 goto 语句从更多内部转移控制 深度嵌套的结构。

【讨论】:

  • 这是避免goto 的一种方法。没有什么方法可以准确地指定break 语句应该中断的控制结构吗?
  • @DanielAllenLangdon:我不相信,也许在某些语言中,但不是 C#。来自msdn.microsoft.com/en-us/library/37zc9d2w%28VS.80%29.aspx“在嵌套语句中,break 语句仅终止立即将其括起来的 do、for、switch 或 while 语句。您可以使用 return 或 goto 语句从更深的嵌套结构中转移控制." 所以即使是 MSDN 也建议使用returngoto 来退出嵌套结构。
  • 并通过该评论,您刚刚回答了我最初的问题。谢谢。
  • 糟糕,在我发布我的答案之前甚至没有看到这个...+1 以获得更广泛的解释。
【解决方案2】:

这种类型的问题是因为想太多了。您可以简单地拥有一个布尔值,如果在 for 循环之前满足您的条件,则该布尔值将被更改,并且仅当布尔值为真时才运行您的方法,例如:

switch(x)
   {
    case 1:
        bool donrun;
        for(int i = 0; i < 10; i++)
        {
            int val = getValue(i);
            if (val == 0)
                donrun = true;
        }
        if(!donrun) doMoreStuff();
        break;
    case 2:
        doSomeThingElse();
        break;
    default: throw new ArgumentOutOfRangeException();
}

【讨论】:

  • 实际上,Daniel 考虑了该选项,但没有发布代码示例:“另一种选择是在 for 循环中跟踪一个单独的变量,但这会增加代码行并且是不那么优雅。” 但我不止一次被抓到这样做>。> 我尽量不这样做。
  • 嗯,一开始我什至看不出他的方法有什么问题……但从美学上讲,我也同意你的方法比这种方法更好。
  • 大部分我同意。这是一个非常微不足道的案例,尤其是如果这只是一个小的私有实现细节,那么这没什么大不了的。根据我的经验,我尽量避免在 switch/case 块中进行尽可能多的工作/混乱,因为很容易迷失在正在发生的事情和跟踪逻辑流程中。将goto 扔进一个开关并没有帮助。更不用说在开关中有一个goto 指向一个case——这是有效的——只是把樱桃放在上面!
  • @Chris,听起来你可能会成为混淆 C 竞赛的优秀选手!
  • @DanielAllenLangdon:工作量太大。这就像故意尝试用互联网速记书写一样。谢谢夸奖!
猜你喜欢
  • 2013-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-19
  • 1970-01-01
  • 1970-01-01
  • 2015-10-30
相关资源
最近更新 更多