【问题标题】:How is switch variable declaration scoped?开关变量声明的范围如何?
【发布时间】:2018-04-03 07:04:36
【问题描述】:

怎么可能跟随?

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 变量。这是编译器语义分析阶段的错误吗?

【问题讨论】:

    标签: c# scope switch-statement variable-declaration c#-7.0


    【解决方案1】:

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

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

    在案例主体中“通常”引入的变量具有整个 switch 语句的范围。

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

    • 能够通过模式匹配引入多个具有相同名称的变量特别有用
    • 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;
    }
    

    可以说编译器可以有一些规则允许你引入多个变量,只要它们是相同的类型——这对于普通代码来说真的很方便。但这肯定会使语言变得更加复杂......


    作为“设计错误”点的一个例子,C# 5 规范实际上有一个错误。 C# 5 规范 (8.7.2) 声称:

    “不失败”规则可防止在意外省略 break 语句时在 C 和 C++ 中出现的一类常见错误。此外,由于这条规则,switch 语句的 switch 部分可以任意重新排列,而不会影响语句的行为。

    无论如何,由于模式匹配排序,这种“任意重新排列”在 C# 7 中是不真实的,但它始终是不真实的。考虑这段代码:

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

    由于奇怪的范围规则,这是有效的 - x 在范围内并且可以在“案例 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 块引入新的变量声明会更有意义空格,或者 C# 无论如何都需要大括号作为 case 块。

    【讨论】:

    • 有趣的是,编译器可以并行处理同一级别的两个空格。对我来说,c#7 有点违反规则,我同意,如果他们从一开始就为每个案例制定不同的范围会更好。
    • “这只是为了防止错误进一步发展” - 完全同意这一点。我很高兴设计团队没有固执己见,并承认他们的错误。
    猜你喜欢
    • 1970-01-01
    • 2013-11-19
    • 1970-01-01
    • 2012-10-15
    • 2012-06-11
    • 1970-01-01
    • 2020-03-18
    • 2014-09-20
    相关资源
    最近更新 更多