为什么C#编译器要求在switch结构中使用break语句?

13

我很难理解为什么编译器要求使用break语句。由于现在不允许出现“穿透”,因此不可能错过它。我明白在C或C++中需要break的原因,但这里是否也需要呢?

为什么在case结束后没有内建的行为来进行break呢?这不只是一种没有实际意义的语法吗?

如果这是一个愚蠢的问题,请原谅。

编辑:只有当case为空时才允许“穿透”。当有语句时,您不能省略break语句。所以,这是一个不同的问题。


3
可能只是为了让C语言的同学们在迁移到新语言时感到满意。不过,我明白你的观点,为什么要强制这样做呢? - Martin Milan
1
我认为这是因为它不可避免地会被那些不太熟悉C#但熟悉C/C++语法的人阅读。即使它没有任何作用,明确的break也有助于所有人的可读性。它实际上是向后兼容的。 - Dolbz
1
简洁的C++社区成员回答:“因为语言需要。” - Greg D
1
@Dolbz:提高可读性是完全合理的目的。 - Sam Harwell
具有C语法和Pascal语义将会令人困惑。 - Carsten S
显示剩余2条评论
4个回答

10

编译器不仅是“需要”break语句,它必须要求它们。

这是一项设计决策。它使代码在语义上更接近C和C++,同时消除了C语言中始终存在的可争议的“穿透”陷阱。


3
你可以这样说。断点可以轻松地由编译器插入,程序员在这里没有选择权。但是,“可读性”是语言结构的重要角色。 - H H
3
@ ThanosPapathanasiou:这没有任何意义。消除break语句并不会让编译器对switch语句做出不同的处理。 - H H
4
灭霸,我也不相信这一点。编译器可以在需要的任何时候假定一个break,并应用其他优化。 - H H
总的来说,我喜欢C#和C语言的语法有很多重叠之处,这使得事情变得简单。因此,如果微软实现了一个不同于switch的定义,即使没有break关键字,也会发生break,我会感到失望。我意识到C#和C并不是彼此的子集或超集,但尽可能保持复制和粘贴的兼容性是很好的。 - Stephen Holt
1
@anthares: 就我个人而言,我认为正确的方法应该类似于C#对switch/break所采取的方法:考虑到程序员可能是想表示10或者12,编译器应该拒绝代码而不是假设任意一种含义。如果编译器能够区分程序员可能想要表示的多个含义,要求程序员在编译代码之前进行歧义消除并不像让编译器接受程序员意图不明的程序那样糟糕。 - supercat
显示剩余7条评论

3
C#中的break语句是该语言创造者的设计决策之一...实际上,他们想要一个“明确无歧义”的break语句,一个只能单向工作的break语句。简而言之,他们不想让程序执行穿透到下一段代码,如果他们没有包含 "break " 而只防止穿透,那么这将会破坏与 C++ 的向后兼容性。

好的,那么为什么这种行为不是内置的,而不需要在情况结尾处显式使用break语句呢?他们可以隐式地做到这一点,对吧? - anthares
2
他们想要明确表示不会掉落。所需的 break 语句是一个声明,表明代码不会掉落。 - Robert Harvey
@RobertHarvey:因为如果语句为空,那么允许穿透。 - Sebastian Mach
@phresnel:从技术上讲,那不是fallthrough;它只是在同一语句上有多个标签。 - Robert Harvey
@RobertHarvey:从技术上讲,如果我跳到一个标签,然后由于缺少“break”而落到下一个case-label,我会认为这是穿透。更具体地说,穿透只是跳转指令(例如break)的缺失。 - Sebastian Mach
@phresnel:“穿过”到另一个标签,中间没有代码,在这个特定的对话中并不重要,无论你如何称呼它。每个人都同意这种“穿透”是毫无争议的。 - Robert Harvey

2
如果case表达式为空,则允许使用Fallthrough。
case Foo:  // fallthrough allowed.
case Bar:
    Console.WriteLine ("Foo or Bar");
    break; // required

“不允许这样做”是一个常见的误解,和“你不能在if条件中赋值”一样。


*实际上你可以这样做。规则只是if条件中只允许布尔值,而x=falsebool x; 一个布尔值。


0

通常这种代码都是个 bug:

// Contrived calculator demostration
decimal x = 5m;
decimal y = 10m;
decimal result = 0m;
string blah = "Divide";

// .. other code omitted

switch(blah) {
    case "Divide":
        result = x / y;

    case "Multiply":
        result = x * y;

    case "Add":
        result = x + y;

    case "Subtract":
        result = x - y;

    default:
        MessageBox.Show("Not a valid operation");

}

然而,编译器不能假设缺少的break是一个错误。就它所知道的而言,你确实希望这些case语句穿透下去。

简单地假设每个case都应该在结尾处加上break只会将一个错误换成另一个错误。

因此,语言设计者禁止了非空case语句的穿透,并在省略它们时抛出错误。

如果需要在非空case之间共享代码,请将其放入一个private(可能是static)方法中,并从那里调用它。

最后一点说明:空case语句的唯一预期行为就是穿透,这也是为什么允许它们存在的原因。


实际上,问题是为什么语言设计者会抛出错误,而不是在完成后隐含地终止您的案例。 - anthares
1
但是“编译器不能假设缺少的breaks是一个bug。”只是因为它是这样写的。由于在非空case中不允许落空,所以问题是为什么编译器会抛出错误而不是假设唯一允许的行为。 - anthares
编译器不能假设缺少的break是一个bug。在它看来,你真的想让这些case穿透到下一个case。仅仅假设break应该在每个case的末尾只会将一个bug换成另一个bug。 - Powerlord
您可以使用goto case语句显式地“穿透”:http://msdn.microsoft.com/zh-cn/library/13940fs2.aspx - Sam Harwell
但这是不同的情况。这是一条指令,将在 case 结束之前执行。因此,它不会干扰我提出的逻辑 - "如果到达 case 的结尾,就放一个 break"。 - anthares

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接