【发布时间】:2020-04-10 04:36:11
【问题描述】:
使用新的 C# 8 使用声明语法,第二个连续 using 语句的包含范围是什么?
TL;DR
在 C# 8 之前,有一个连续的 using 语句,例如:
using(var disposable = new MemoryStream())
{
using(var secondDisposable = new StreamWriter(disposable))
{}
}
将扩展为类似以下内容 (My Source):
MemoryStream disposable = new MemoryStream();
try {
{
StreamWriter secondDisposable = new StreamWriter(disposable);
try{
{}
}
finally {
if(secondDisposable != null) ((IDisposable)secondDisposable).Dispose();
}
}
}
finally {
if(disposable != null) ((IDisposable)disposable).Dispose();
}
我知道还有另外两种可能的扩展,但它们都大致是这样的
升级到 C# 8 后,Visual Studio 提供了一个代码清理建议,我不确定我是否认为这是一个等效建议。
它将上述连续的 using 语句转换为:
using var disposable = new MemoryStream();
using var secondDisposable = new StreamWriter(disposable);
对我来说,这会将第二个的范围更改为与第一个相同的范围。在这种情况下,它可能会巧合地以正确的顺序处理流,但我不确定我是否喜欢依赖那个快乐的巧合。
要明确 VS 要求我做什么:我首先转换了内部(这是有道理的,因为内部仍然包含在外部的范围内)。然后我转换了外部(这在本地是有意义的,因为它仍然包含在方法的范围内)。这两个清理的组合是我很好奇的。
我也认识到我对此的想法可能会略微(甚至是戏剧性地)偏离,但据我今天的理解,这似乎并不正确。我的评估中缺少什么?我不在基地吗?
我唯一能想到的是,在声明语句之后的所有内容的扩展中都插入了某种隐式范围。
【问题讨论】:
-
这是一个小问题,但值得一提。在 C# 中,作用域被定义为程序文本的区域,在该区域中,事物可以通过其非限定的简单名称来引用。您使用范围来表示“局部变量的生命周期”。这两件事之间存在联系,因为局部变量声明空间和这些变量的名称范围是程序文本的同一区域。但请记住,C# 允许延长或缩短局部变量的生命周期,以使该生命周期不同于控制在范围。
-
我的观点是,将“使用”视为“当控制离开变量范围时处理”可能会令人困惑。正如您所注意到的,“使用”实际上是一个try-finally,它在控制进入finally 时释放。同样,这与 变量 的生命周期独立,该变量持有对正在处置的资源的引用。该变量的生命周期可以延长!
-
@EricLippert “C# 8 中的新功能”文档 here 将 using 声明描述为“...告诉编译器所声明的变量应放置在封闭范围的末尾” .这和你的观点有冲突吗?
-
啊,在查看我的 cmets 时,我发现我无意中通过尝试更精确而使事情变得不必要地更加混乱;我的错。对
Dispose的调用将在控制离开范围时发生,即使变量的生命周期被延长,这就是我应该强调的。您在问题中表达的担忧是关于处置发生的时间,而不是变量的生命周期。抱歉,如果这令人困惑。 -
好吧,我现在意识到我在第四段中埋下了头,因为我担心的是
Dispose而不是范围本身。
标签: c# visual-studio visual-studio-2019 c#-8.0