c# - 为什么不能在 C# 中没有大括号的 switch 部分中使用 using 变量?
问题描述
考虑以下代码:
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 对新using
语句的语言提议给出了这样的解释:
由于其实际生命周期的复杂性,
using
直接在标签内声明是非法的。case
一种可能的解决方案是简单地赋予它与out var
在同一位置的 a 相同的寿命。人们认为功能实现的额外复杂性和解决工作的容易性(只需在case
标签上添加一个块)并不能证明采用这条路线是合理的。
举个例子,考虑一下这个......
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
to的跳转case_1
被明确定义为导致fs4
's 处置...... - ……不清楚……
- 控件遇到时是否
fs1
应立即处理goto case_4
(后case_1:
) - 是否
fs3
应该在从case_1:
to跳转时初始化,case_4:
因为它会在范围内(忽略它未使用的事实)。 - 是否
fs1
应该在case 3
和中初始化case 4
,即使严格来说它在范围内。
- 控件遇到时是否
因为链接的规范提案只显示了一个块 之前goto
的一个点(因此该语句的主题将超出范围),而在这种情况下,它没有明确定义,如果并且仍然在范围内(或不在范围内)向前跳跃的时候。using
using
fs1
fs3
请记住,using;
对象应该在超出范围时被释放,而不是在它最后一次在声明的范围内使用时应该被释放(这将禁止将其传递给仍在使用它的另一个方法)。
对于可能/应该发生的事情,至少有两个论据:
fs1
跳到 时立即处理case_3
,即使fs1
在技术上仍然在范围内(如果您订阅“所有案例共享相同范围”的思想流派)。using;
这也忽略了将其主题的生命周期严格绑定到封闭范围的语句的要点。
仅在控制离开整个块
fs1
时才switch
释放(即使fs1
在此之前可以说是超出范围。
正如提案所提到的,这是可以敲定的,但考虑到语言设计团队的时间限制,人们可能不会同意。
推荐阅读
- c# - 在 C# 中的 DataTable 中动态添加数据
- graphql - 带有休息客户端的 Gentics Mesh 中的无效 graphql 请求
- angularjs - 从 JSON 转换“attrs.$observe”返回值时,“JSON 意外结束”输入
- java - 使用 OnStartupTriggeringPolicy 和 DirectWriteRolloverStrategy 删除旧日志文件
- amazon-web-services - 使用 SAM 或 Cloudformation 将一个堆栈的输出用作其他堆栈中 lambda 的环境变量
- android - 如何在 Android 的 Google MAP 上为某个国家/地区生成 GeoJSON 文件
- c# - 每 200 毫秒多次 Ajax 调用导致运行几分钟后延迟
- ios - Objective-C Deleted UILocalNotification 删除后仍然出现
- scala - 解析解析结果时返回类型错误
- c# - 路由到 Razor Pages 中的属性