在c#中对同一作用域使用多个using语句时,是否保证调用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?

换句话说,stf2的Dispose()方法保证首先被调用,然后stf1的Dispose()方法保证被第二个调用?(基本上:Dispose()方法的调用顺序与它们所属对象的分配顺序相反?)

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

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

你会很清楚事情发生的顺序(不是我推荐那种特殊的结构),因为它和下面这个完全一样:

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

对于using也是如此。您的代码与以下代码没有什么不同:

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

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

是的,stf2。首先调用Dispose,然后调用stf1。处理

using语句被转换为try-finally。这只是语法糖…因此,您是正确的,因为您的示例将在编译时翻译为以下内容:

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

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

即使您没有在外部块上为Stuff1使用大括号,它仍然是相同的,如果你做了

由于可能重新排序,无法保证。在结束花括号(或在示例中是隐式花括号)上调用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

下运行

是的,Dispose方法将在using作用域的末尾被调用,所以Dispose()方法将按照它们所属对象的分配顺序被调用

最新更新