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()メソッドが2番目に呼び出されることが保証されていますか? (基本的に:Dispose()メソッドは、オブジェクトが属するオブジェクトの割り当ての逆の順序で呼び出されますか?)

3

6 答え

usingステートメントは他のブロックレベルのステートメントと同じです。次のようなコードを書いた場合:

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

    }

物事がどのような順序で起こるかはあなたには分かりますが(これは私がその特定の構造を推奨するものではありません)、それはまさにこれと同じです。

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

    }
}

したがって、 using があります。あなたのコードは以下のものと変わりありません:

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

    }
}

ここでは、内部使用ブロックが最初に終了することが完全にはっきりしているので、リソースは最初に処理する必要があります。

6
追加された
素晴らしいもの:-)ありがとう!
追加された 著者 user972301,

はい、stf2.Disposeが最初に呼び出され、その後stf1.Dispose

2
追加された
答えをありがとう:)
追加された 著者 user972301,

とにかく、usingステートメントはtry-finallyに変換されます。その構文的な砂糖..あなたの例はコンパイル時に次のように翻訳されるので、正しいです:

try
{
    Stuff1 stf1 = new Stuff1());
    try
    {
        Stuff2 stf2 = new Stuff2();
    }
    finally
    {
        stf2.Dispose();
    }
}
finally
{
    stf1.Dispose();
}
2
追加された
usingステートメントは魔法のようなものですが、この説明はその動作をはっきりと明白にしています。ありがとう。
追加された 著者 Rob Elliott,
OK。私はC ++の世界から来て、明示的なDispose()呼び出しをすべてのオブジェクトに書く必要がないようなパターンを試したかったのです...デストラクタと似ています。コンストラクタで以前に設定された値。ありがとう!
追加された 著者 user972301,

Stuff2は内部ブロックにあるため、Stuff1の前に配置されます。

Stuff1の外側のブロックにカッコを使用していないにもかかわらず、それはあなたが行ったのと同じです。

1
追加された
すばらしいです!情報をありがとう!
追加された 著者 user972301,

可能な再注文による保証はありません。 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(); }

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

1
追加された
Disposeは確定的に呼び出され、暗黙的なコードブロックがあります。#2の意味は#1の前にブロックを終了します。
追加された 著者 Andrew Barber,
私がC ++世界から来ているので、私は興味があります。どのような場合、この「並べ替え」が起こるでしょうか?
追加された 著者 user972301,
OK。 Disposeの呼び出し順序はシングルスレッドモードでのみ保証されています。知っておいてよかった。
追加された 著者 user972301,

はい。Disposeメソッドはusingスコープの最後で呼び出されるため、Dispose()メソッドはそのオブジェクトが属するオブジェクトの割り当ての逆の順序で呼び出されます

0
追加された