为什么C#允许在案例之后而不允许在案例之前进行陈述?
为什么C#允许这样做: 但不是这个:为什么C#允许在案例之后而不允许在案例之前进行陈述?,c#,.net,switch-statement,C#,.net,Switch Statement,为什么C#允许这样做: 但不是这个: 因为缩进有误导性,第一个代码实际上是: var s = "Nice"; switch (s) { case "HI": break; const string x = "Nice"; case x: Console.Write("Y"); break; } 也就是说,x在case语句中声明(尽管在break之后),在该语句中它是有效的。但是,直接在开关语句中无效–唯一有效的语句
因为缩进有误导性,第一个代码实际上是:
var s = "Nice";
switch (s)
{
case "HI":
break;
const string x = "Nice";
case x:
Console.Write("Y");
break;
}
也就是说,x
在case
语句中声明(尽管在break
之后),在该语句中它是有效的。但是,直接在开关
语句中无效–唯一有效的语句是大小写
和默认值
此外,const
声明在编译时进行求值,因此即使前面有break
语句,也定义了x
但是,请注意,Mono C#编译器不会编译此代码,它抱怨“名称“
x
”在当前范围内不存在”,因此Mono似乎比.NET编译器实现了更多的检查。但是,我在C#标准中找不到任何禁止使用const
声明的规则,因此我假设.NET编译器是正确的,Mono编译器是错误的。因为语言规范不允许在开关中直接使用const(只允许大小写和默认值):
其中:
表达式:
整数或字符串类型的表达式。语句:
如果控制权转移到案例或默认值,则要执行的嵌入式语句。跳转语句:
将控制权从箱体中转移出去的跳转语句。常量表达式:
根据此表达式的值将控件转移到特定案例
在第一种情况下,常量是案例逻辑的一部分。常量将只起作用,因为它是在编译时而不是在运行时重写的。。。。因为
开关
会执行此操作
jump_to_the_label_matchig(s)
{
label1:
...
done_quit_this;
label2:
...
done_quit_this;
d'oh:
...
done_quit_this;
}
而不是这个
now_jump_to_the_label_matchig(s)
{
le'mme_wander_around_doing_things_that_could_have_been_done_before_me;
label1:
...
done_quit_this;
label2:
...
我敢打赌,如果这是允许的,你会发现人们愿意在那里做他们所有的编程工作:-)任何其他语言都允许吗?你为什么要这样做?是否有人会写这样的代码,这仍然是一个有趣的问题。在幕后一定有一些奇怪的范围界定工作。@r case语句之所以需要是编译时常量,是因为
switch
的实现是一个字典,而不是一系列if/else if
语句。它需要它们生成一个可以作为字典键的对象。同样重要的是,没有评估案例的副作用,因为当测试用例时,这些副作用不会产生,比如说C++,谢谢你发布这个问题;我将把这一个添加到我的开关古怪和微妙的单声道错误列表中。如果您对switch语句的不寻常用法感兴趣,请参阅我关于该主题的文章:但如果它真的中断了,它为什么会显示y?@rtunerconst
语句不是在运行时执行的,而是在编译时替换的。试着在它上面放一个断点。但是为什么在断点之后和下一个案例之前允许任何代码?@Magnus为什么允许你在返回之后放代码代码>在该范围结束之前?这是无法运行的代码。答案很简单,因为他们没有费心将其定为非法;将其定为非法不仅仅是离开它,而且离开它并不会真正引起问题。禁止它的功能请求根本不值得努力去实现。最后一段:的确,Mono在这里似乎是错误的。但人们很难责怪他们;这是一个奇怪的场景。我想知道Mono是否对switch语句中的作用域的其他规则有错误?我会发现的!
switch (expression)
{
case constant-expression:
statement
jump-statement
[default:
statement
jump-statement]
}
jump_to_the_label_matchig(s)
{
label1:
...
done_quit_this;
label2:
...
done_quit_this;
d'oh:
...
done_quit_this;
}
now_jump_to_the_label_matchig(s)
{
le'mme_wander_around_doing_things_that_could_have_been_done_before_me;
label1:
...
done_quit_this;
label2:
...