提问人:geekley 提问时间:1/5/2023 更新时间:1/5/2023 访问量:636
何时处置“using var”?是尽快超出范围还是在块结束时?
When is a `using var` disposed? Is it out-of-scope as soon as possible or at the end of the block?
问:
本地的生存期将延长到声明它的作用域的末尾。然后,当地人将按照他们申报的相反顺序进行处置。
using
using
我的问题是:什么时候本地被认为是超出范围的?
它一定是在区块的尽头吗?
它是否一定是在块中最后一次使用后就对的?
或者它是实现定义的,因此它可以是其中之一,甚至可以介于两者之间?using
换言之:
{
using var res = Res();
res.DoStuff();
somethingElse.DoWhatever();
res.DoMoreStuff();
// 100 more statements that have nothing to do with res
}
这总是等价于这个(1)吗?
{
using (var res = Res()) {
res.DoStuff();
somethingElse.DoWhatever();
res.DoMoreStuff();
// 100 more statements that have nothing to do with res
}
}
还是总是这样(2)?
{
using (var res = Res()) {
res.DoStuff();
somethingElse.DoWhatever();
res.DoMoreStuff();
}
// 100 more statements that have nothing to do with res
}
或者这是一个实现细节?
规范是否对此进行了定义?从技术上讲,这样的“范围”是什么?如果上述情况之一总是如此,那么是否有理由更喜欢这种行为而不是另一种行为?我认为(2)更好,但也许我错了。
我知道对于高级编程来说,它可能没有太大变化,但我很好奇。
答:
3赞
Sweeper
1/5/2023
#1
根据语言规范,这就是 Scope 的含义:
名称的范围是程序文本的区域,在该区域中可以引用由名称声明的实体,而无需对名称进行限定。
[...]
在local_variable_declaration中声明的局部变量的作用域 (§12.6.2) 是发生声明的块。
请注意,声明只是添加到局部变量声明中的单词。根据使用声明提案,using
using
该语言将允许添加到局部变量声明中。
using
因此,您的声明等同于using
{
using (var res = Res()) {
res.DoStuff();
somethingElse.DoWhatever();
res.DoMoreStuff();
// 100 more statements that have nothing to do with res
}
}
最外层表示一个块。{ ... }
评论
0赞
geekley
1/5/2023
好的,但是这真的能保证语法添加的隐式 Dispose 只会在 100 个语句之后调用吗?我不相信编译器不可能将其“优化”为 (2),即可能在块结束之前但在我不再引用它之后调用 Dispose(它在功能上等同于“超出范围”)。在实际规范中是否有隐式 try-finally 真正延伸到整个块末尾的保证?using var
0赞
geekley
1/5/2023
我说“实际规格”是因为我不确定问题中链接的页面是否是“最终”/最终规格......它奇怪地按 C# 版本拆分,并且在 URL 中有“提案”,它们看起来更像是草稿。但是我找不到其他任何东西,所以也许它们是整个正式规范......?
1赞
Sweeper
1/5/2023
@geekley目前没有“实际规格”,只有草稿。他们仍在为 C# 7 编写规范,此功能在 C# 8 中。请耐心等待:)至于在区块结束前不移动电话,提案中的措辞几乎是你现在能得到的保证。这不是优化。从 (1) 更改为 (2) 会完全改变程序行为。想想如果抛出异常会发生什么。Dispose
res.DoStuff();
0赞
geekley
1/13/2023
啊,我明白了。因此,规范保证如果抛出异常,100 条语句将不会运行。感谢您澄清 (1) 和 (2) 在功能上是不同的。现在这很有意义!
0赞
geekley
3/9/2023
不,等等。现在我很困惑。我真的认为 (1) 和 (2) 在功能上是等价的。如果抛出异常,则在这两种情况下都会发生相同的情况:100 个语句不会以任何一种方式运行(无论是在 Dispose 之前还是在之后),因为这并不意味着 .唯一的区别是,在成功执行时,(2) 调用 Dispose earlier no?你能解释一下你的意思吗?using
catch
0赞
T.S.
1/5/2023
#2
另外,关于
然后,当地人将按照他们申报的相反顺序进行处置。
using
using (var v1 = Class1()) // disposed third
using (var v2 = Class2()) // disposed second
using (var v3 = Class3()) // disposed first
{
. . . .
}
1赞
tymtam
1/5/2023
#3
在 .NET 博客的 Do more with patterns in C# 8.0 中,我们可以阅读:
using 声明只是前面带有 using 关键字的局部变量声明,其内容在当前语句块的末尾进行处理。
然后我们可以看到:
static void Main(string[] args)
{
using var options = Parse(args);
if (options["verbose"]) { WriteLine("Logging..."); }
} // options disposed here
评论