代码之家  ›  专栏  ›  技术社区  ›  Luke Vo

为什么在没有大括号的C#中不能在switch部分中使用using变量?

  •  2
  • Luke Vo  · 技术社区  · 4 年前

        switch ("")
        {
            case "":
                using var s = new MemoryStream();
    
                break;
        }
    

    上面的代码无法编译,并出现以下错误:“不能在switch节中直接使用using变量(请考虑使用大括号)”。

        switch ("")
        {
            case "":
                {
                    using var s = new MemoryStream();
                }
                
                // break can be inside or outside the braces
                break;
        }
    
    1 回复  |  直到 4 年前
        1
  •  4
  •   Dai    4 年前

    C# 8.0's language proposal for the new using statement 给出如下解释:

    A 直接在 case out var 在同一个地方。它被认为是特性实现的额外复杂性和解决方法的简单性(只需在 案例 label)没有理由走这条路。


    作为一个例子,考虑一下。。。

    switch( foo )
    {
    case 1: // Yeah, I'm in the tiny minority who believe `case` statements belong in the same column as the `switch` keyword.
    case 2:
        using FileStream fs1 = new FileStream( "foo.dat" );
        goto case 4;
    
    case 3:
        using FileStream fs3 = new FileStream( "bar.dat" );
        goto case 1;
    
    case 4:
        using FileStream fs4 = new FileStream( "baz.dat" );
        if( GetRandomNumber() < 0.5 ) goto case 1;
        else break;
    }
    

    …相当于这个伪代码(忽略序列 if 逻辑):

    if( foo == 1 || foo == 2 ) goto case_1;
    else if( foo == 3 ) goto case_3;
    else if( foo == 4 ) goto case_4;
    else goto after;
    
    {
    case_1:
        using FileStream fs1 = new FileStream( "foo.dat" );
        goto case_4;
    
    case_3:
        using FileStream fs3 = new FileStream( "bar.dat" );
        goto case_1;
    
    case_4:
        using FileStream fs4 = new FileStream( "baz.dat" );
        if( GetRandomNumber() < 0.5 ) goto case_1;
        else goto after;
    }
    after:
    

    …规范中说“与在 语句位于同一位置。”,因此,如果我正确理解规范,则上面的代码将与以下代码相同:

    if( foo == 1 || foo == 2 ) goto case_1;
    else if( foo == 3 ) goto case_3;
    else if( foo == 4 ) goto case_4;
    else goto after;
    
    {
    case_1:
        using( FileStream fs1 = new FileStream( "foo.dat" ) )
        {
            goto case_4;
    
    case_3:
            using( FileStream fs3 = new FileStream( "bar.dat" ) )
            {
                goto case_1;
            }
            
    case_4:
            using( FileStream fs4 = new FileStream( "baz.dat" ) )
            {
                if( GetRandomNumber() < 0.5 ) goto case_1;
                else goto after;
            }
        }
    }
    after:
    

    认为 问题是:

    • case_4 case_1 很好地定义了 fs4 的处置。。。
      • 是否 fs1 当控件遇到时应立即处理 goto case_4 (之后 case_1: )
      • 是否 fs3 case_4: 因为它在范围内(不管它没有被使用)。
      • 是否 在中时应初始化 case 3 case 4

    因为链接的规范建议只显示 goto 到一定程度 之前 使用 阻塞(因此 使用 可行性研究1 向前跳 .

    using; 表示当对象超出作用域时应将其释放,而不是在它声明的范围中最后一次使用该对象时应将其释放(这将禁止将其传递给仍在使用它的另一个方法)。

    至少有两个论据可以/应该发生什么:

    1. 处置 可行性研究1 case_3 尽管如此 可行性研究1 在技术上仍然在范围内(如果你同意“所有案例都有相同的范围”的思想)。

      • 使用;
    2. 处置 可行性研究1 只有 switch 阻止(即使可以说 在此之前超出了范围。

    同意 考虑到语言设计团队的时间限制。