web-dev-qa-db-ja.com

usingステートメントの終了前に戻るとどうなりますか?処分が呼び出されますか?

私は次のコードを持っています

_using(MemoryStream ms = new MemoryStream())
{
     //code
     return 0;
}
_

dispose()メソッドは、usingステートメントの最後で呼び出されます_}_正しいですか? returnステートメントの終わりの前にusingがあるので、MemoryStreamオブジェクトは適切に破棄されますか?そこで何が起こるの?

109
NLV

はい、Disposeが呼び出されます。ブロックの実行の終了、usingステートメント、または例外など、ブロックを離れるのにどのような意味があるかに関係なく、実行がreturnブロックのスコープを離れるとすぐに呼び出されます。

@Noldorinが正しく指摘しているように、コードでusingブロックを使用するとtry/finallyにコンパイルされ、Disposeブロックでfinallyが呼び出されます。たとえば、次のコード:

using(MemoryStream ms = new MemoryStream())
{
     //code
     return 0;
}

事実上:

MemoryStream ms = new MemoryStream();
try
{
    // code
    return 0;
}
finally
{
    ms.Dispose();
}

したがって、finallyブロックは、tryブロックの実行が完了した後に実行されることが保証されているため、実行パスに関係なく、Disposeが呼び出されることが保証されます。

詳細については、 このMSDN記事 を参照してください。

補遺:
追加する必要がある注意事項:Disposeは必ず呼び出されるため、Disposeを実装するときにIDisposableが例外をスローしないようにすることをお勧めします。残念ながら、コアライブラリには、Disposeが呼び出されたときに特定の状況でdoをスローするクラスがいくつかあります。WCFサービスリファレンス/クライアントプロキシを探しています。 -そして、例外スタックのアンワインド中にDisposeが呼び出された場合、元の例外はDispose呼び出しによって生成された新しい例外を優先して飲み込まれるため、元の例外を追跡することは非常に困難です。それは途方もなくイライラすることができます。それとも、イライラするほど腹立たしいですか? 2つのうちの1つ。多分両方。

160
Randolpho

usingステートメントはtry ... finallyブロックとまったく同じように動作するため、常にコード出口パスで実行されます。ただし、finallyブロックが呼び出されない非常に少数のまれな状況の対象になると思います。私が覚えている1つの例は、バックグラウンドスレッドがアクティブな間にフォアグラウンドスレッドが終了した場合です。GC以外のすべてのスレッドは一時停止します。つまり、finallyブロックは実行されません。

Obvious edit:これらは、IDisposableオブジェクトを処理できるようにするロジックを除き、同じように動作します。

ボーナスコンテンツ:スタック可能(タイプが異なる場合):

using (SqlConnection conn = new SqlConnection("string"))
using (SqlCommand comm = new SqlCommand("", conn))
{

}

また、コンマ区切り(タイプが同じ場合):

using (SqlCommand comm = new SqlCommand("", conn), 
       SqlCommand comm2 = new SqlCommand("", conn))
{

}
18

MemoryStreamオブジェクトは適切に破棄されるので、心配する必要はありません。

4
Otávio Décio

usingステートメントを使用すると、オブジェクトは完了パスに関係なく破棄されます。

参考文献...

3
RSolberg

コンパイル後、リフレクターのコードを見てください。コンパイラーはコードをリファクタリングして、ストリームでdisposeが呼び出されるようにします。

0
Wil P