开关变量声明的范围如何?

How is switch variable declaration scoped?

跟随怎么可能?

switch (param.ParameterType)
{
    case Type x when x == typeof(byte):
        int invalid;
        break;
    case Type x when x == typeof(short):
        int invalid;
        break;
    case Type x when x == typeof(int):
        break;
    case Type x when x == typeof(long):
        break;
}

问题是,x 如何在没有任何可见块的情况下限定每个案例的范围。同时,变量 invalid 不能在不同的 switch case 中声明。它必须在一个块内。

如果没有块,则不可能遵循变量范围。

{
    // case byte:
    Type x;
    int invalid;
    // break;

     // case short:
    Type x; // x can not be declared twice.
    int invalid;
}

如果每种情况都有不可见的块,那么下面一定是可能的(但不是)。

{
    {   // block for each case.
        // case byte:
        Type x;
        int invalid;
        // break;
    }

    {
        // case short:
        Type x;
        int invalid; // but this throws compile time error.
    }
}

似乎编译器在这里做了一些魔术,显然 x 的作用域不同于 invalid 变量。这个错误是在编译器的语义分析阶段吗?

Question is, how is x scoped inside each case without any visible blocks. meanwhile, variable invalid cant be declared in different switch cases. it has to be inside a block.

在 case 标签中通过模式匹配引入的变量仅具有该 case 主体的范围。

案例主体中引入的变量 "normally" 具有整个 switch 语句的作用域。

是的,它不一致 - 但我认为:

  • 能够通过模式匹配引入同名的多个变量特别有用
  • case 语句中引入的变量作用域从一开始就是一个设计错误,这只是为了防止错误进一步发展

请注意,对于使用相同 case 块的 case,您不能使用模式匹配多次声明同一个变量。例如,通过简化您的代码,这很好:

object o = null;
switch (o)
{
    case Type x when x == typeof(byte):
        break;
    case Type x when x == typeof(short):
        break;
}

但这不是:

object o = null;
switch (o)
{
    case Type x when x == typeof(byte):
    case Type x when x == typeof(short):
        break;
}

可以说编译器 可以 有一些规则允许您引入多个变量,只要它们属于同一类型 - 这对于通用代码来说可能非常方便。但这肯定会使语言变得更加复杂...


作为 "design mistake" 点的一个例子,C# 5 规范实际上有一个错误。 C# 5 规范 (8.7.2) 声明:

The “no fall through” rule prevents a common class of bugs that occur in C and C++ when break statements are accidentally omitted. In addition, because of this rule, the switch sections of a switch statement can be arbitrarily rearranged without affecting the behavior of the statement.

无论如何,由于模式匹配顺序,此 "arbitrary rearrangement" 在 C# 7 中是不正确的,但它始终是不正确的。考虑这段代码:

class Test
{
    static void Main(string[] args)
    {
        switch (args.Length)
        {
            case 0:
                string x;
                break;
            case 1:
                x = args[0];
                break;
        }
    }
}

这是有效的,因为奇怪的范围规则 - x 在范围内并且可以在 "case 1" 块中使用。但是,如果您重新排列大小写:

class Test
{
    static void Main(string[] args)
    {
        switch (args.Length)
        {
            case 1:
                x = args[0]; // Invalid
                break;
            case 0:
                string x;
                break;
        }
    }
}

...这现在给出了一个编译时错误。该变量仍在范围内(编译器知道您所说的 x 是什么意思)但是您不能在局部变量声明之前为其赋值。

据我所知,从来没有人想要使用由较早范围声明的变量 - 对于每个 case 块来说更有意义引入一个新的变量声明 space,或者 C# 无论如何都需要 case 块的大括号。