web-dev-qa-db-ja.com

.NETでDispose(bool disposing)をオーバーライドする意味は何ですか?

IDisposableを実装するクラスをC#で記述した場合、単に実装するだけでは十分ではない理由

public void Dispose(){ ... } 

アンマネージリソースの解放を処理するには?

です

protected virtual void Dispose(bool disposing){ ... }

常に必要な場合もあれば、必要な場合もあれば、それ以外に何か必要な場合もあります。

41
Mark Carpenter

厳密には必要ありません。これは、推奨される使い捨てパターンの一部です。これに関するフレームワークのデザインガイドラインのセクションを読んでいない場合は(初版の9.3、第2版はお手数ですがごめんなさい)、お読みください。 このリンクを試す

使い捨てのクリーンアップとファイナライズ可能なガベージコレクションは、ゴミ箱の私を区別するのに役立ちます。

あなたはそれをそのようにする必要はありませんが、あなたはそれを読んで、それが不必要に割り引かれる前にこれが推奨される理由を理解するべきです。

31
Hamish Smith

ファイナライザ、新しい仮想メソッドの導入、元の破棄メソッドの「シーリング」を含む完全なパターンは、すべてのベースをカバーする非常に汎用的な目的です。

アンマネージリソース( ほぼnever である必要があります)にdirectハンドルがない場合は、ファイナライザが必要です。

あなたがあなたのクラスを封印するならば(そして可能な限りクラスを封印することについての私の見解はおそらく今ではよく知られているでしょう 継承のために設計するかそれを禁止する )仮想メソッドを導入する意味がありません。

最後にIDisposableを「複雑な」方法で実装したのか、最も明白な方法で実装したのかを思い出せません。

public void Dispose()
{
    somethingElse.Dispose();
}

注意すべきことの1つは、本当に堅牢なコードを作成する場合は、すべきです後は何もしないでください。破棄され、必要に応じてObjectDisposedExceptionをスローします。これは、世界中の開発者が使用するクラスライブラリには良いアドバイスですが、これが自分のワークスペース内で使用されるクラスになるだけの場合、ほとんどメリットがありません。

43
Jon Skeet

MSFTのドキュメントには、使い捨てのパターンに関するバイアスが少しあります。 IDisposableを実装する理由は2つあります。

  1. IDisposableを実装するタイプのフィールドがあります
  2. ファイナライザを持っています。

ケース1は、ほとんどのコードでかなり一般的です。ケース2は、Microsoftが作成するコードではかなり一般的です。それらは、ファイナライズが必要なアンマネージリソースのマネージラッパーを記述したものです。しかし、コードでは非常に珍しいはずです。結局のところ、これらのすべてのNice .NETクラスを使用して、汚れた作業を行うことができます。 Dispose()メソッドを呼び出すだけです。

ケース2のみが使い捨てパターンを必要とします。マイクロソフトはそれをたくさん使う必要があります。ほとんどの場合、単純なDispose()が必要になります。

14
Hans Passant

他の優れた回答に加えて、次の記事を確認することをお勧めします。

5
Hosam Aly

Boolを破棄する追加の方法は、フレームワークの設計ガイドラインのどこかから出てきました。これは、クラスが例外をスローせずにdisposeメソッドを複数回呼び出せるようにするための単なるパターンです。絶対に必要というわけではありません。技術的には、disposeメソッドで実行できます。

3
Bob

他の人が言ったことを拡大するだけです:あなたがしないだけではありませんneed 'complex dispose'、それはあなたが実際にはそれを望まないです理由。

「複雑な破棄」ルートに進み、ファイナライザを実装した後、オブジェクトを明示的に破棄するのを忘れた場合、オブジェクト(およびオブジェクトが参照するもの)は、実際に破棄される前に余分なGC生成を生き延びます(1つにぶら下がる必要があるため) CLRがファイナライザを呼び出すための時間が長くなります)。これは、必要のないメモリ負荷を引き起こすだけです。さらに、オブジェクトのヒープ全体でファイナライザを呼び出すと、かなりのコストがかかります。

したがって、あなた(またはあなたの派生型)がアンマネージリソースを持っていない限り、避けてください。

ああ、そして私たちがこの分野にいる間、他のユーザーからのイベントを処理するクラスのメソッドは、クラスが破棄された後に呼び出される前に「安全」でなければなりません。最も簡単なのは、クラスが破棄された場合に何もしないことです。 http://blogs.msdn.com/ericlippert/archive/2009/04/29/events-and-races.aspx を参照してください

1
piers7

クラスがIDisposable.Dispose()を実装していて、派生クラスが追加のロジックを追加する必要がある場合、そのクラスは、派生クラスがチェーンできるDisposeメソッドの種類を公開する必要があります。一部のクラスは、パブリックIDisposable.Dispose()メソッドがなくてもDispose()を実装する可能性があるため、protectedのすべての実装で、IDisposableメソッドがあるかどうかに関係なく、Disposeである仮想メソッドがあると便利です。か否か。ほとんどの場合、bool引数は実際には意味がありませんが、protected virtual Dispose(bool)に、公開されている可能性がある、または公開されていないDispose()

protected virtual Dispose(bool)を使用しないクラスでは、派生クラスが、規則とは異なる方法でクリーンアップロジックを処理する必要があります。 C++/CLIのような一部の言語は、その規則に従うIDisposable実装を拡張するためだけに装備されているため、非標準の実装からクラスを派生できない場合があります。

1
supercat

これにより、ファイナライズとは無関係にDispose()で作業を行い、アンマネージリソースをクリーンアップすることができます。

ファイナライザで「自分」以外の管理対象オブジェクトに対してanythingを実行することは非常に...予測不可能です。これのほとんどは、ファイナライザーがAppDomainのステージ2シャットダウンで非決定的な方法で呼び出されるためです-したがって、ファイナライザーが呼び出されると、まだ参照しているオブジェクトがすでに存在している可能性が非常に高いです。確定。

同じメソッドへのDispose呼び出しとファイナライザ呼び出しの両方をディスパッチすると、シャットダウンコードを共有できます。ブールパラメータを使用すると、マネージクリーンアップがある場合はスキップできます。

また、メソッドの仮想性により、継承者が独自のクリーンアップコードを追加する簡単な方法が提供され、誤って自分のものを呼び出さないというリスクが少なくなります。

1
kyoryu