web-dev-qa-db-ja.com

C#でIDisposableとデストラクタを使用することの違いは何ですか?

デストラクタではなく、クラスにIDisposeをいつ実装しますか? この記事 を読みましたが、まだポイントがありません。

私の前提は、オブジェクトにIDisposeを実装すると、ガベージコレクターが実行するのを待つのではなく、明示的に「破壊」できるということです。これは正しいです?

これは、オブジェクトに対してDisposeを常に明示的に呼び出す必要があるということですか?これのいくつかの一般的な例は何ですか?

95
Jordan Parmer

ファイナライザ(デストラクタ)はガベージコレクション(GC)の一部です-GCが主にメモリ不足の結果として発生するため(つまり、より多くのスペースが必要)、これが発生する(または発生する場合でも)不確定です。管理対象リソースには独自の収集/廃棄があるため、ファイナライザは通常、unmanagedリソースのクリーンアップにのみ使用されます。

したがって、IDisposable決定論的にオブジェクトのクリーンアップに使用されます。オブジェクトのメモリ(まだGCに属している)を収集しませんが、たとえば、ファイル、データベース接続などを閉じるために使用されます。

これに関する多くの以前のトピックがあります。

最後に、IDisposableオブジェクトにファイナライザーもあることは珍しくありません。この場合、Dispose()は通常GC.SuppressFinalize(this)を呼び出します。これは、GCがファイナライザを実行しないことを意味します-単にメモリを破棄します(はるかに安価です)。オブジェクトをDispose()するのを忘れた場合、ファイナライザは引き続き実行されます。

118
Marc Gravell

Finalize()メソッドの役割は、.NETオブジェクトがアンマネージリソースをクリーンアップできるようにすることですガベージコレクション時。ただし、ガベージコレクションに依存する代わりに、データベース接続やファイルハンドラなどのオブジェクトをできるだけ早く解放する必要があります。そのためには、IDisposableインターフェイスを実装し、Dispose()メソッドでリソースを解放する必要があります。

23
Igal Tabachnik

[〜#〜] msdn [〜#〜] には非常に優れた説明があります。

このインターフェイスの主な用途は、アンマネージリソースを解放することです。ガベージコレクターは、管理対象オブジェクトが使用されなくなると、管理対象オブジェクトに割り当てられたメモリを自動的に解放します。ただし、ガベージコレクションがいつ発生するかを予測することはできません。さらに、ガベージコレクターは、ウィンドウハンドルなどのアンマネージリソース、またはopen filesおよびストリーム。

このインターフェイスのDisposeメソッドを使用して、ガベージコレクタと一緒にアンマネージリソースを明示的に解放します。オブジェクトのconsumerは、オブジェクトが不要になったときにこのメソッドを呼び出すことができます。

9
abatishchev

C#デストラクタにあるべき唯一のものはこの行です:

Dispose(False);

それでおしまい。このメソッドには他に何も入れないでください。

8
Jonathan Allen

常にDisposeを呼び出すべきかどうかに関するあなたの質問は、白熱した議論です。 .NETコミュニティの尊敬される個人からの興味深い視点については、 this ブログを参照してください。

個人的には、Disposeの呼び出しは必須ではないというJeffrey Richterの立場は信じられないほど弱いと思います。彼は自分の意見を正当化するために2つの例を挙げています。

最初の例では、主流のシナリオでは、Windows FormsコントロールでDisposeを呼び出すことは退屈で不要であると述べています。ただし、主流のシナリオでは、Disposeが実際にコントロールコンテナーによって自動的に呼び出されることに言及していません。

2番目の例では、開発者がIAsyncResult.WaitHandleは、プロパティが待機ハンドルを遅延初期化することを認識せずに積極的に破棄し、不要なパフォーマンスの低下を招く必要があります。ただし、この例の問題は、IAsyncResult自体がIDisposableオブジェクトを処理するためにMicrosoftが公開しているガイドラインに準拠していないことです。つまり、クラスがIDisposable型への参照を保持している場合、クラス自体はIDisposableを実装する必要があります。 IAsyncResultがその規則に従った場合、独自のDisposeメソッドが、その構成要素のどれを破棄する必要があるかを決定できます。

だから誰かがより説得力のある議論をしない限り、私は「常に廃棄」と呼ばれるキャンプに留まり、ほとんどがデザインの悪い選択から生じるいくつかのフリンジケースがあるだろうということを理解しています。

4
Brian Gideon

本当に簡単です。回答済みであることは知っていますが、もう一度試してみますが、可能な限りシンプルにしようとします。

通常、デストラクタは使用しないでください。 .netが実行したいだけです。ガベージコレクションサイクルの後にのみ実行されます。アプリケーションのライフサイクル中に実際に実行されることはありません。このため、実行する必要のあるデストラクタにコードを配置しないでください。また、実行時に存在するクラス内の既存のオブジェクトに依存することはできません(デストラクタの実行順序が保証されていないため、既にクリーンアップされている場合があります)。

IDisposibleは、クリーンアップが必要なリソース(ファイルとグラフィックスハンドルなど)を作成するオブジェクトがある場合は常に使用する必要があります。実際、デストラクタに入れるものはすべて、上記の理由によりIDisposableにする必要があると多くの人が主張しています。

ほとんどのクラスは、ファイナライザが実行されるときにdisposeを呼び出しますが、これは単に安全なガードとして存在するため、決して依存しないでください。完了したら、IDisposableを実装するものはすべて明示的に破棄する必要があります。 IDisposableを実装する場合は、ファイナライザーでdisposeを呼び出す必要があります。例については、 http://msdn.Microsoft.com/en-us/library/system.idisposable.aspx を参照してください。

2
DaEagle

ここに、IDisposable、GC、および廃棄物を取り巻くミストの一部をきれいにする別の素晴らしい記事があります。

Chris Lyons WebLog Demystifying Dispose

0
scope_creep