私は次のコードを持っています
_using(MemoryStream ms = new MemoryStream())
{
//code
return 0;
}
_
dispose()
メソッドは、using
ステートメントの最後で呼び出されます_}
_正しいですか? return
ステートメントの終わりの前にusing
があるので、MemoryStream
オブジェクトは適切に破棄されますか?そこで何が起こるの?
はい、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つ。多分両方。
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))
{
}
MemoryStreamオブジェクトは適切に破棄されるので、心配する必要はありません。
using
ステートメントを使用すると、オブジェクトは完了パスに関係なく破棄されます。
参考文献...
コンパイル後、リフレクターのコードを見てください。コンパイラーはコードをリファクタリングして、ストリームでdisposeが呼び出されるようにします。