为什么C#允许在一个案例之后但不在它之前的语句?

rtu*_*ner 64 .net c# switch-statement

为什么C#允许这样:

var s = "Nice";
switch (s)
{
    case "HI":
        break;
    const string x = "Nice";
    case x:
        Console.Write("Y");
        break;
}
Run Code Online (Sandbox Code Playgroud)

但不是这个:

var s = "Nice";
switch (s)
{
    const string x = "Nice";
    case x:
        Console.Write("Y");
        break;
}
Run Code Online (Sandbox Code Playgroud)

Kon*_*lph 119

因为你的缩进是误导性的,所以第一个代码实际上是:

var s = "Nice";
switch (s)
{
    case "HI":
        break;
        const string x = "Nice";
    case x:
        Console.Write("Y");
        break;
}
Run Code Online (Sandbox Code Playgroud)

也就是说,x在声明中case声明(虽然在a之后break),它在有效的地方.然而,直接在里面switch的语句是无效的-唯一有效的语句有casedefault.

此外,const声明在编译时进行评估,因此x即使break之前有声明,也会定义声明.

但请注意,Mono C#编译器不会编译此代码,它抱怨" x当前作用域中不存在"名称' ,因此Mono似乎实现了比.NET编译器更多的检查.但是,我在C#标准中找不到禁止使用该const声明的任何规则,因此我假设.NET编译器是正确的并且Mono编译器是错误的.

  • 为了解决你的最后一段:事实上,Mono似乎在这里出错了.但人们很难责怪他们; 这是一个奇怪的场景.我想知道Mono是否得到关于在switch语句中确定范围错误的其他规则?我会发现的! (22认同)
  • @rtuner`const`语句不在运行时执行,它们在编译时被替换.尝试并给它一个断点. (21认同)
  • @Magnus为什么你允许在`return;`之后和该范围结束之前放置代码?它的代码无法运行.答案很简单,因为他们并不打算将其视为非法; 使它成为非法是比离开它更多的工作,离开它并不会真正导致问题.禁止它的功能请求不值得实施. (14认同)
  • 但_why_是休息后和下一个案例之前允许的任何代码吗? (6认同)
  • 但它怎么会显示y,如果它确实破坏了? (2认同)
  • @Magnus因为它会导致"无法访问"的代码,在该位置无效. (2认同)
  • @ChibuezeOpata非法的唯一原因是因为有了这个改变,第二种情况不会评估为编译时常量.如果你在第二种情况下不使用`x`那么代码编译得很好,即使有了这个改变.这表明这个答案*是正确的. (2认同)
  • @ChibuezeOpata实现是case语句后面可以跟任意数量的语句.它实际上确实进行了可达性检查,它会生成一个警告,说明给定的行无法访问,但即使它检测到无法访问的代码,它也不会产生错误.他们为什么要花费额外的时间和精力将警告变成错误?它有什么收获?如果您可以证明这一点,那么请继续向Microsoft提出建议. (2认同)
  • @fourpastmidnight:对,没有任何可执行文件无法访问,因此警告被禁止. (2认同)

Pet*_*ter 7

因为语言规范不允许在您的交换机中直接使用const(仅允许大小写和默认值):

switch (expression)
{
   case constant-expression:
      statement
      jump-statement
   [default:
      statement
      jump-statement]
}
Run Code Online (Sandbox Code Playgroud)

哪里:

expression:整数或字符串类型表达式.
statement:如果控件转移到大小写或默认情况下要执行的嵌入语句.
jump-statement:将控制权移出案件主体的跳转声明.
constant-expression:根据此表达式的值将控制转移到特定情况.

在第一种情况下,const是案例逻辑的一部分.const只会起作用,因为它是在编译时而不是在运行时重写的.