ステートメントの使用が終了する前に戻るとどうなりますか?破棄は呼び出されますか?


115

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

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

dispose()この方法は、の終了時に呼び出されるusing文のかっこ}右?I以来 returnの終了前にusing声明、うMemoryStreamオブジェクトが適切に配置されても?そこで何が起こるの?


4
@JonH:完全に重複しているものを見つけ、投票して投票してください。
Noldorin

@Noldorin:以前に尋ねられたはずだと思ったので、私はこれのだましを探しに行きましたが、それを見つけることができませんでした。そこにはまだ簡単な質問があると思います。:)
ランドルフォ

@JonHと@Noldorin-質問が作成されたときに重複が表示され、「類似の質問」を検索します。この機能は、人々が十分に使用していないようです。
アダムホールズワース2010

@アダム:自分で試してみてください。タイトルをコピーして貼り付け、システムによってどの重複が表示されるかを確認します。ヒントをあげましょう。答えはありません。GoogleまたはSOの検索を介して検索する場合は、同上。この質問以前に尋ねられたことがないようです。
Randolpho

ああ...私はそれを取り戻します。私はいくつかの非常に専用の検索した後、近くの重複が見つかりました:stackoverflow.com/questions/2641692/...は今、質問は完全に異なって尋ねているが、究極の質問はほとんど同じです。結局これはだましだと考えることができると思います。
Randolpho

回答:


167

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

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

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私はあなたを見てる、WCFサービス参照/クライアントプロキシ-と呼ばれているが!-その場合Dispose、元の例外がDispose呼び出しによって生成された新しい例外のために飲み込まれるため、例外スタックのアンワインド中に呼び出された場合、元の例外を追跡することは非常に困難です。それは手に負えないほどイライラすることがあります。それともイライラさせられますか?2つのうちの1つ。多分両方。


4
最終的にDisposeinの呼び出しでtry-finallyブロックに効果的にコンパイルされているので、説明したように、の実装が効果的に機能していることがわかりfinallyます。
ノルドリン

@Noldorin:正確に。私はそれについて明確にすることができると思いますが。編集今後....
Randolpho

1
また、Environment.FailFastを使用したり、StackOverFlowExceptionが発生した場合など、finallyブロックの実行が保証されない状況もあることに注意してください。
Christopher McAtackney、2010

@ C.McAtackney:良い点も。また、IIRC、OutOfMemoryException; 基本的に、それが重大な実行エラーであるために例外をキャッチできない場合、Disposeは呼び出されません。もちろん、そのような場合、プログラムとそれに割り当てられたメモリがクラッシュすることが保証されているので、99.9%の場合は、disposeメソッドでファイルに書き込むなどの奇妙なことを行わない限り、問題ではありません。 。壊滅的なプログラムのクラッシュは別として、それはです。
Randolpho

WCFで 'using()'ステートメントを使用しないでください。詳細については、この記事を参照しください。これは、WCFプロキシに使用するスニペットです。 'WCFProxy variableName = null; {variableName = new WCFProxy();を試してください。//ここでTODOコードvariableName.Proxy.Close(); variableName.Dispose(); }キャッチ(例外){if(variableName!= null && variableName.Proxy!= null){variableName.Proxy.Abort(); }投げる; } '
Dave Black

18

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

明らかな編集: IDisposableオブジェクトを処理するロジックを除いて、それらは同じように動作します。

ボーナスコンテンツ:スタックできます(タイプが異なる場合):

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

}

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

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

}



0

コンパイル後、リフレクターでコードを確認してください。コンパイラーがコードをリファクタリングして、ストリームでdisposeが呼び出されることを確認します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.