Switch statement fallthrough in C#?
switch语句fallthrough是我喜欢
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | static string NumberToWords(int number) { string[] numbers = new string[] {"","one","two","three","four","five", "six","seven","eight","nine" }; string[] tens = new string[] {"","","twenty","thirty","forty","fifty", "sixty","seventy","eighty","ninety" }; string[] teens = new string[] {"ten","eleven","twelve","thirteen","fourteen","fifteen", "sixteen","seventeen","eighteen","nineteen" }; string ans =""; switch (number.ToString().Length) { case 3: ans += string.Format("{0} hundred and", numbers[number / 100]); case 2: int t = (number / 10) % 10; if (t == 1) { ans += teens[number % 10]; break; } else if (t > 1) ans += string.Format("{0}-", tens[t]); case 1: int o = number % 10; ans += numbers[o]; break; default: throw new ArgumentException("number"); } return ans; } |
聪明人之所以畏缩,是因为
编译器失败,错误如下:
1 2 | Control cannot fall through from one case label ('case 3:') to another Control cannot fall through from one case label ('case 2:') to another |
为什么?如果没有三个
(复制/粘贴我在别处提供的答案)
通过
1 2 3 4 5 6 7 8 9 10 11 12 | switch (/*...*/) { case 0: // shares the exact same code as case 1 case 1: // do something goto case 2; case 2: // do something else goto default; default: // do something entirely different break; } |
"为什么"是为了避免意外摔倒,对此我很感激。在C和Java中,这是一个不常见的bug来源。
解决方法是使用goto,例如
1 2 3 4 5 6 7 8 | switch (number.ToString().Length) { case 3: ans += string.Format("{0} hundred and", numbers[number / 100]); goto case 2; case 2: // Etc } |
在我看来,交换机/机箱的总体设计有点不幸。它离C太近了——在作用域等方面可以进行一些有用的更改。可以说,更智能的开关可以进行模式匹配等是有用的,但这实际上是从开关变为"检查一系列条件"——此时可能会调用不同的名称。
切换失败历来是现代软件中的主要缺陷源之一。语言设计人员决定强制在案例结束时跳转,除非您默认直接进入下一个案例而不进行处理。
1 2 3 4 5 | switch(value) { case 1:// this is still legal case 2: } |
为了增加这里的答案,我认为有必要结合这个问题来考虑另一个问题,即。为什么C一开始就允许摔倒?好的。
当然,任何编程语言都有两个目标:好的。
因此,任何编程语言的创建都是如何最好地服务于这两个目标之间的平衡。一方面,它更容易转化为计算机指令(无论是机器代码、像IL这样的字节码,还是在执行时解释的指令),那么编译或解释过程将更有效率、可靠和紧凑的输出。从极端的角度来看,这个目标导致我们只是在汇编、IL甚至原始操作代码中编写代码,因为最简单的编译就是根本没有编译的地方。好的。
相反,语言表达程序员意图的越多,而不是为此目的所采取的手段,在编写和维护程序时,程序就越容易理解。好的。
现在,
在这种情况下,允许坠落的原因有两个:好的。
不管怎样,这是自然发生的:如果您将一个跳转表构建成一组指令,并且早期的一批指令中没有包含某种跳转或返回,那么执行将自然地进入下一批。如果您使用机器代码将使用C的
在汇编中编写代码的程序员已经习惯了同样的做法:在汇编中手工编写跳转表时,他们必须考虑给定的代码块是以返回、跳出表还是继续下一个块结尾。因此,让编码人员在必要时添加一个明确的
因此,在当时,平衡计算机语言的两个目标是一种合理的尝试,因为它既与生成的机器代码有关,也与源代码的表达有关。好的。
不过,四十年后,情况并不完全相同,原因有几个:好的。
关于最后两点,请考虑一下K&R当前版本的以下引用:好的。
Falling through from one case to another is not robust, being prone to disintegration when the program is modified. With the exception of multiple labels for a single computation, fall-throughs should be used sparingly, and commented.
Ok.
As a matter of good form, put a break after the last case (the default here) even though it's logically unnecessary. Some day when another case gets added at the end, this bit of defensive programming will save you.
Ok.
所以,从马的口中,通过C是有问题的。最好的做法是总是用注释来记录掉掉的地方,这是一种应用一般原则的做法,即一个人应该记录自己做了不寻常的事情的地方,因为这将使以后的代码检查和/或使你的代码看起来像是有一个新手的错误,当它实际上是正确的时候。好的。
当你想到这一点时,就要这样编码:好的。
1 2 3 4 5 6 7 8 9 | switch(x) { case 1: foo(); /* FALLTHRU */ case 2: bar(); break; } |
添加一些东西使代码中的fall-through显式化,但编译器无法检测到(或检测到其缺失)。好的。
因此,事实上,on必须在c中明确表示fall through,这不会给那些用其他c风格语言写得很好的人增加任何惩罚,因为他们在fall through中已经明确了。好的。
最后,这里使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | switch(x) { case 0: case 1: case 2: foo(); goto below_six; case 3: bar(); goto below_six; case 4: baz(); /* FALLTHRU */ case 5: below_six: qux(); break; default: quux(); } |
在这种情况下,如果我们希望一个块包含在为值执行的代码中,而不仅仅是将值带到前面的块中,那么我们已经不得不使用
综上所述:好的。
总之,一个相当合理的设计决策好的。
*有些形式的basic允许人们做像
?达夫的装置再次出现在这里,作为一个合理的例外。事实上,有了这种模式和类似的模式,就有了重复的操作,即使没有对这种效果做出明确的评论,也能使fall-through的使用相对清晰。好的。好啊。
您可以"转到案例标签"http://www.blackwasp.co.uk/csharpgoto.aspx
The goto statement is a simple command that unconditionally transfers the control of the program to another statement. The command is often criticised with some developers advocating its removal from all high-level programming languages because it can lead to spaghetti code. This occurs when there are so many goto statements or similar jump statements that the code becomes difficult to read and maintain. However, there are programmers who point out that the goto statement, when used carefully, provides an elegant solution to some problems...
他们在设计上忽略了这种行为,以避免在遗嘱没有使用这种行为,但却造成了问题。
它只能在案例部分没有语句时使用,如:
1 2 3 4 5 6 | switch (whatever) { case 1: case 2: case 3: boo; break; } |
他们改变了C语句的切换语句(从C//爪哇/ C++)的行为。我想原因是人们忘记了摔倒和失误。我读到的一本书说用goto来模拟,但这对我来说似乎不是一个好的解决方案。
开关(C参考)表示
C# requires the end of switch sections, including the final one,
因此,您还需要将一个
只需添加一个简短的注释,Xamarin的编译器实际上弄错了这个错误,并且它允许执行fallthrough。它应该已经被修复了,但还没有被释放。在一些代码中发现了这一点,编译器没有抱怨。
你可以通过GOTO关键字实现像C++一样的下降。
前任:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | switch(num) { case 1: goto case 3; case 2: goto case 3; case 3: //do something break; case 4: //do something else break; case default: break; } |
在每个case语句之后,即使它是默认情况,也需要break或goto语句。
A jump statement such as a break is
required after each case block,
including the last block whether it is
a case statement or a default
statement. With one exception, (unlike
the C++ switch statement), C# does not
support an implicit fall through from
one case label to another. The one
exception is if a case statement has
no code.
--c switch()文档
C不支持通过switch/case语句执行fall through。不知道为什么,但确实没有人支持。连杆机构
您忘记在案例3中添加"break;"语句。在案例2中,您将它写到if块中。因此,请尝试以下方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | case 3: { ans += string.Format("{0} hundred and", numbers[number / 100]); break; } case 2: { int t = (number / 10) % 10; if (t == 1) { ans += teens[number % 10]; } else if (t > 1) { ans += string.Format("{0}-", tens[t]); } break; } case 1: { int o = number % 10; ans += numbers[o]; break; } default: { throw new ArgumentException("number"); } |