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

卡泽姆·阿赫加里

怎么可能?

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不能在不同的切换情况下声明变量它必须在一个块内。

如果没有块,则不可能对变量进行范围界定。

{
    // 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变量不同这个错误在编译器的语义分析阶段内吗?

乔恩·斯基特

问题是,在没有任何可见块的情况下,x的作用域如何?同时,在不同的切换情况下不能声明变量无效。它必须在一个块内。

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

在案例主体中“通常”引入的变量具有整个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#来说,都需要大括号会更有意义。反正情况下。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章