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

标签 c# switch-statement grammar using-statement

考虑以下代码:

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

            break;
    }
上面的代码无法编译并出现以下错误:“不能在 switch 部分中直接使用 using 变量(考虑使用大括号)”。
修复程序已经在建议中,但我的问题是为什么下面的代码是合法的,而上面的不是?为什么 C# 不能只允许以前的代码?
    switch ("")
    {
        case "":
            {
                using var s = new MemoryStream();
            }
            
            // break can be inside or outside the braces
            break;
    }

最佳答案

C# 8.0's language proposal for the new using statement给出了这样的解释:

A using declaration is illegal directly inside a case label due to complications around its actual lifetime. One potential solution is to simply give it the same lifetime as an out var in the same location. It was deemed the extra complexity to the feature implementation and the ease of the work around (just add a block to the case label) didn't justify taking this route.



举个例子,考虑一下这个......
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:
...规范说“与在同一位置的 using 语句中声明变量具有相同的效果。”,所以如果我正确理解规范,上面的代码将与此相同:
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: 之后)
  • 是否fs3case_1: 跳转时应该完全初始化至case_4:因为它会在范围内(忽略它未使用的事实)。
  • 是否fs1应该在 case 3 中初始化和 case 4 ,即使严格来说它在范围内。


  • 因为链接的规范提案只显示了一个向后的 gotousing 之前的一点 block (因此 using 语句的主题将超出范围),而在这种情况下,如果 fs1 则没有明确定义和 fs3向前跳跃时仍在范围内(或不在范围内)。
    请记住 using;说对象应该在它超出范围时被释放,而不是在它最后一次在它声明的范围内使用时应该被释放(这将禁止将它传递给仍在使用它的另一个方法)。
    对于可能/应该发生的事情,至少有两个论据:
  • 处置fs1只要它跳转到 case_3 , 即使 fs1仍然在技术范围内(如果您订阅“所有案例共享相同范围”的思想流派)。
  • 这也忽略了 using; 的要点将其主题的生命周期严格绑定(bind)到封闭范围的语句。

  • 处置fs1仅当控制权离开整个 switch block (尽管可以说 fs1 在此之前超出范围。

  • 正如提案所提到的,这是可以敲定的,但考虑到语言设计团队的时间限制,人们可能不会同意。

    关于c# - 为什么不能在 C# 中没有大括号的 switch 部分中使用 using 变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65316260/

    相关文章:

    c# - 从 aspx 页面发布到外部 url 时如何不传递 View 状态

    c++ - switch 语句直接转到 default

    c# - 使用 switch 语句的最佳实践是什么?嵌套?具体的?

    java - 使用antlr4的二义性语法

    regex - 将正则表达式转换为CFG

    c - 如何定义排除某组词的文法?

    c# - 如何使用 CodeDOM 定位特定语言版本?

    c# - 在离屏位图上应用像素着色器

    C# GUI 入门教程

    使用 switch 语句将两位数字转换为单词