【问题标题】:Why do you need to put break after the last label of a switch statement?为什么需要在 switch 语句的最后一个标签之后放置 break?
【发布时间】:2010-08-11 04:07:56
【问题描述】:

编译器肯定知道它是switch 语句的最后一个标签吗?

【问题讨论】:

  • 它是帮助你的程序员,而不是编译器。如果您在此之后添加另一个语句并忘记中断怎么办?
  • @Byron:那将是 C# 中的编译错误,不是吗?所以你会注意到。
  • @Thilo - 仅仅因为它是一个编译错误并不意味着编译器需要它。编译时错误比运行时错误更容易更正且成本更低。这就是微软将其包含在语言规范中的原因。参见 c/c++。
  • @Byron:这就是我的意思。编译错误和中断的要求是为了帮助程序员(与您提到的错误很容易发生的 C/C++ 相反)。我认为我们在同一页上。 (顺便说一下,C# 语言设计者为此 +1,我希望 Java 人也有同样的想法。这是打破与 C 语法向后兼容性的好案例)

标签: c# switch-statement


【解决方案1】:

这是因为在 C++ 中会发生这种情况:

switch(a)
{
     case 1:
        // do stuff

     case 2:
        // do other stuff
}

如果a 为 1,那么 - 根据 C++ 规则 - “做事”和“做其他事”都会发生。为了让 C++ 程序员开始使用 C# 时不会被绊倒(并使代码更清晰),C# 要求您明确指定是要使用 break 还是使用不同的标签。

现在,至于为什么您需要在 last 块上使用 break,这是一个简单的一致性问题。它还使重构更容易:如果您移动案例,您不会因为缺少break 语句而突然出现错误。另外,当您想添加另一个标签等时会发生什么。

【讨论】:

  • 我说的是在最后一个标签之后。没有更多的标签可以通过,因此不需要 break 语句。
【解决方案2】:

在你的 switch 的最后一个 case 语句之后休息一下是好的defensive programming。如果将来可能在下面添加另一个 case 语句,它将消除上述案例中程序流程失败的风险。

【讨论】:

  • MS 说默认总是最后评估:“默认情况可以在 switch 语句中以任何顺序出现。不管它在源代码中的顺序如何,它总是最后评估,在所有案例标签都已经评估。”所以你的推理是不正确的。
【解决方案3】:

一致性。与在最后一个枚举定义之后或在带有大括号的对象实例化语句中的最后一个赋值之后能够有一个逗号的原因相同。最后一种情况可能并不总是最后一种情况。

它也使特殊情况减少。

如果是这样,那么学习、写作或阅读会更容易。虽然这增加了一致性。

【讨论】:

    【解决方案4】:

    在C# switch statements 中,您必须明确声明要中断或转到另一种情况或转到默认值。

    在 C 和 C++ 中,switch 语句会不间断地通过标签。在 C# 中,让用户明确说出他们想要做什么对于避免错误很重要。例如,很多用户从 C++ 转向 C#。


    关于您要询问的最后一个案例陈述。我能想到 3 个很好的理由。

    1. 在任何语言中保持一致很重要。
    2. 如果您稍后在它之后附加另一个案例,应该如何处理默认值?
    3. 为什么要默认设置中断?为什么不去?这里有歧义。

    【讨论】:

    • 这是一个 C# 问题。但无论如何,为什么编译器需要在最后一个标签之后中断?
    • 它不需要它,但语言需要它。
    【解决方案5】:

    根据http://msdn.microsoft.com/en-us/library/06tc147t.aspx

    您不能“通过”任何开关部分,包括最后一个。

    可以通过以下任何一种方式避免跌倒:break、goto 或 return。

    【讨论】:

    • 哈哈。我只是指网站所说的,而不是聪明的。
    【解决方案6】:

    其实有一种情况是不用放break的

    考虑这段代码:

    using System;
    
    public class Program
    {
        public static void DoStuff()
        {
        }
    
        public static void DoAnotherStuff()
        {
        }
    
        public static void Main()
        {
            switch(1)
            {
                case 1: DoStuff(); break;
                default: DoAnotherStuff();
            }
        }
    }
    

    使用 C# 4.0 编译器只会给你一个不错的 CS0162: Unreachable code warning

    看来,由于 switch 有一个常量表达式,编译器已经知道它将执行的路径,然后忽略默认标签。

    很酷的是,如果将 switch(1) 更改为 switch(2),它将不再编译,因为默认标签缺少中断。

    编辑:来自C# Reference

    C# 中的要求是每个 switch 部分的结尾,包括最后一个,都是不可到达的。虽然通常使用跳转语句来满足这一要求,但以下情况也是有效的,因为无法到达语句列表的末尾。

    case 4:
        while (true)
            Console.WriteLine("Endless looping. . . .");
    

    这就解释了为什么默认不需要中断。事实上,任何无法到达的标签都不需要 break、return 或 goto

    【讨论】:

    • "这解释了为什么默认不需要中断。事实上,任何无法访问的标签都不需要中断、返回或 goto" 但它没有解释,为什么我们需要在 可达代码。无论如何,很酷的帖子。
    【解决方案7】:

    当使用switch 时,break 不是唯一的选择。您还可以选择转到另一个案例、转到默认案例、转到另一个标签或返回。也可能有多个具有单个实现主体的案例。由于最多有五个选项以及一个实现具有多个案例的能力,因此编译器无法简单地输入“正确”答案。

    你必须选择你打算做什么。它确保编译器做正确的事情,使你的代码更清晰,并且更难做愚蠢的程序员事情,比如在“最后一个”之后添加另一个案例,而忘记放入 break/goto/return。

    【讨论】:

      【解决方案8】:

      根据 Eric Lippert 的 this blog post(案例 2),它允许您任意重新排序开关部分,而不会意外引入重大更改:

      [编译器]要求每个 switch 部分, 包括最后一个,有一个 无法到达的终点。的目的 这条规则,以及没有失败的 一般来说,我们想要你 能够任意重新排序 你的开关部分没有 不小心引入了中断 改变。

      【讨论】:

        【解决方案9】:

        如前所述,您可以使用 default:,但也可以考虑 case null。 case null:确实需要休息;

        案例为空: iEvaluatedToNothing(); 休息;

        如果你想“瀑布”下来,你可以这样做;

        switch (deliverMail)
        {
            case null:
            case "":
            case "Address0":
                deliverMail0();
                goto case "1";
            case "1":
                deliverMail1();
                break;
        }
        

        您可以根据需要将其与中断一起使用,但在最后一次评估时需要一个。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-02-12
          • 2018-10-14
          • 2023-02-10
          • 2018-09-17
          • 1970-01-01
          • 2018-02-26
          • 2011-01-22
          相关资源
          最近更新 更多