在c#中对同一作用域使用多个using语句时,是否保证调用Dispose()方法的顺序?
本文关键字:调用 是否 Dispose 顺序 方法 语句 作用域 using | 更新日期: 2023-09-27 18:12:41
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()方法将按照它们所属对象的分配顺序被调用