在 C# 中对同一作用域使用多个 using 语句时,是否可以保证调用 Dispose() 方法的顺序?

发布于 2024-12-12 11:44:46 字数 543 浏览 0 评论 0原文

using (Stuff1 stf1 = new Stuff1(...)) // Allocation of stf1
using (Stuff2 stf2 = new Stuff2(...)) // Allocation of stf2
{
    try
    {
        // ... do stuff with stf1 and stf2 here ...
    }
    catch (Stuff1Exception ex1)
    {
        // ...
    }
    catch (Stuff2Exception ex2)
    {
        // ...
    }
} // Automatic deterministic destruction through Dispose() for stf1/stf2 - but in which order?

换句话说,是否保证首先调用 stf2 的 Dispose() 方法,然后保证其次调用 stf1 的 Dispose() 方法? (基本上:Dispose() 方法是按照与其所属对象的分配相反的顺序调用的?)

using (Stuff1 stf1 = new Stuff1(...)) // Allocation of stf1
using (Stuff2 stf2 = new Stuff2(...)) // Allocation of stf2
{
    try
    {
        // ... do stuff with stf1 and stf2 here ...
    }
    catch (Stuff1Exception ex1)
    {
        // ...
    }
    catch (Stuff2Exception ex2)
    {
        // ...
    }
} // Automatic deterministic destruction through Dispose() for stf1/stf2 - but in which order?

In other words, is stf2's Dispose() method guaranteed to be called first and then stf1's Dispose() method guaranteed to be called second? (basically: Dispose() methods being called in reverse order of the allocation of the object that they belong to?)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

挽清梦 2024-12-19 11:44:47

using 语句与其他块级语句没有什么不同。如果您编写这样的代码:

if (...)
    if (...)
    {

    }

您会很清楚事情发生的顺序(并不是我会推荐该特定结构),因为它与此完全相同:

if (...)
{
    if(...)
    {

    }
}

所以它是使用using。您的代码与以下代码没有什么不同:

using (...)
{
    using(...)
    {

    }
}

在这里,很明显内部 using 块首先终止,因此应该首先释放它的资源。

using statements are no different than other block level statements. If you wrote code like this:

if (...)
    if (...)
    {

    }

It would be clear to you what order things take place (not that I would recommend that particular structure), because it's exactly the same as this:

if (...)
{
    if(...)
    {

    }
}

So it is with using. Your code is no different than the following:

using (...)
{
    using(...)
    {

    }
}

Here, it is perfectly clear that the inner using block terminates first, and so it's resource should be disposed first.

薄情伤 2024-12-19 11:44:47

是的,首先调用 stf2.Dispose,然后调用 stf1.Dispose

Yes, stf2.Dispose is called first and after that it is called stf1.Dispose

花心好男孩 2024-12-19 11:44:47

无论如何,using 语句都会转换为 try-finally 。它只是语法糖..所以你是正确的,你的例子在编译时将被翻译如下:

try
{
    Stuff1 stf1 = new Stuff1());
    try
    {
        Stuff2 stf2 = new Stuff2();
    }
    finally
    {
        stf2.Dispose();
    }
}
finally
{
    stf1.Dispose();
}

The using statement is converted to try-finally anyway. Its just syntactic sugar.. so you are correct in that your example would be translated as the following at compile time:

try
{
    Stuff1 stf1 = new Stuff1());
    try
    {
        Stuff2 stf2 = new Stuff2();
    }
    finally
    {
        stf2.Dispose();
    }
}
finally
{
    stf1.Dispose();
}
野味少女 2024-12-19 11:44:47

Stuff2 将在 Stuff1 之前被处理,因为它位于内部块中。

即使您没有在 Stuff1 的外部块上使用大括号,它仍然与您使用大括号时一样。

Stuff2 will be disposed before Stuff1 because it is in an inner block.

Even though you didn't use braces on the outer block for Stuff1, it's still the same as if you did.

隱形的亼 2024-12-19 11:44:47

由于可能重新订购,不提供任何保证。在结束卷曲(或您的示例中的隐式卷曲)上调用 Dispose。您将始终在非优化的调试版本中看到预期的顺序。您可以使用 Thread.MemoryBarrier 来强制操作顺序。

using (Stuff1 stf1 = new Stuff1(...)) // Allocation of stf1
using (Stuff2 stf2 = new Stuff2(...)) // Allocation of stf2
{ {
    try
    {
        // ... do stuff with stf1 and stf2 here ...
    }
    catch (Stuff1Exception ex1)
    {
        // ...
    }
    catch (Stuff2Exception ex2)
    {
        // ...
    }
} Thread.MemoryBarrier(); }

释放模式优化的方式是保证在所有指令完成后该线程上的结果可预测。其他一切(从单独核心上的不同线程查看)都可供争夺。从另一个线程观察到,stf2 尚未释放但 stf1 已释放的情况并不违反规则。除非你强制执行操作顺序。尝试编写一些断言并在 Jinx 下运行

No guarantee due to possible reordering. Dispose is called on a closing curly (or an implicit one in your example). You will always see the expected order in non-optimized Debug builds. You could use Thread.MemoryBarrier to force the order of operations.

using (Stuff1 stf1 = new Stuff1(...)) // Allocation of stf1
using (Stuff2 stf2 = new Stuff2(...)) // Allocation of stf2
{ {
    try
    {
        // ... do stuff with stf1 and stf2 here ...
    }
    catch (Stuff1Exception ex1)
    {
        // ...
    }
    catch (Stuff2Exception ex2)
    {
        // ...
    }
} Thread.MemoryBarrier(); }

Release-mode optimizations are done in such a way as to guarantee predictable results on this thread after all instructions complete. Everything else (view from a different thread on a separate core) is up for grabs. It's not against the rules to have a situation where stf2 is not yet disposed, but stf1 is disposed, as observed from another thread. Unless you force the order of operations. Try writing some asserts and running under Jinx

浅浅 2024-12-19 11:44:47

是的,Dispose 方法将在 using 作用域结束时被调用,因此 Dispose() 方法的调用顺序与其所属对象的分配顺序相反

Yes, the Dispose method will be called in the end of the using scope, so Dispose() methods being called in reverse order of the allocation of the object that they belong to

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文