0

を実装するC#クラスがIDisposableあり、実装では、も実装するサブオブジェクトDispose()を呼び出します。Dispose()IDisposable

同じクラスのデストラクタはどうですか?そこで何か特別なことをする必要がありますか?

4

3 に答える 3

1

C# デストラクタ構文は、コンパイラに override を指示しますObject.Finalize()。オーバーライドするクラスObject.Finalize()は「ファイナライザー」を持つと言われます。そのようなオブジェクトはすべて「ファイナライズ キュー」と呼ばれる特別なリストに配置され (リストには意味的に関連する順序がないため、「キュー」という用語はおそらく少し奇妙です)、「ファイナライズ可能」としてマークされます。ガベージ コレクションが実行されると、システムは、ファイナライズ キューの外側に直接または間接の強い参照が存在するすべてのオブジェクトにタグを付けることから始めます。. 次にシステムは、ファイナライズ可能なすべてのオブジェクトを調べて、まだタグ付けされているかどうかを確認します。そうでない場合は、「ファイナライズ不可」とマークされますが、「freachable [eff-reachable] キュー」と呼ばれるキューに追加されます。最後に、システムは、freachable キュー内のすべてのオブジェクトに「ライブ」のタグを付け、タグの付いていないオブジェクトをすべて破棄し、freachable キューが空でない場合は、スレッドをディスパッチして、Finalizeそこに含まれるすべてのアイテムの呼び出しを開始します。「freachable queue」にあるオブジェクト、およびそれらが強い参照を保持しているすべてのオブジェクトは、「生きている」と見なされることに注意してください。Finalize()メソッドが実行されました。それらは「ファイナライズ不可」とマークされているため、「ファイナライズ可能」として再マークされているか、それらへの強い参照がライブオブジェクトに保存されていない限り、その後はガベージコレクションの対象になります。

「デストラクタ」または「ファイナライザ」は、オブジェクトの破棄を早めることに注意してください。代わりに、破棄されたはずのオブジェクトにメソッドを実行する猶予を与えますFinalize()(C# プログラムの場合は、コードを実行します)。デストラクタ)。これは、ファイナライザーを持つオブジェクトが、(1) ユニバースの終了前に発生する必要があること、(2) 他のオブジェクトが実行しないこと、および (3) 任意の範囲内で安全に実行できることを知っている場合に役立ちます。不明なスレッド コンテキスト。ファイナライザーを呼び出しに使用することはめったにないことに注意してくださいIDisposable.Dispose他のオブジェクトで。そのようなオブジェクトが任意のスレッド コンテキストからの破棄を処理できる場合、それらはおそらく自分自身をファイナライズできます (したがって、それらの破棄は要件 2 を満たしていません)。任意のスレッド コンテキストからの破棄を処理できない場合、ファイナライザー内で破棄することはできません (要件 #3)。

ちなみに、Microsoft は .net の開発の早い段階で、ファイナライザーを実装するIDisposableがファイナライザーを持たないクラスは、派生クラスがファイナライザーを追加できるように規定を作成する必要があると考えていたようDisposeで、これを考慮したパターンを推奨し続けています。派生クラスが破棄されていないオブジェクトで呼び出された場合に何らかの警告を生成する「アラームベル」ファイナライザーを持つと便利な場合がありますが、自明ではないクラスから派生したクラスをお勧めしますファイナライザーを持たないクラスは、ファイナライズ メソッドまたはデストラクタ内でクリーンアップを実行しようとしないでください。ファイナライズには、継承チェーンのすべてのステップで完全に処理されない場合、Heisenbugs (予測不可能な失​​敗) を引き起こす可能性のあるトリッキーなコーナー ケースが含まれます。. 基本クラスが信頼性の高いファイナライズのクリーンアップをサポートするように設計されていない場合、派生クラスにファイナライザーを追加すると、そうでなければ機能していたはずのコードが壊れる可能性があります。

于 2012-06-01T15:23:13.097 に答える
0

いいえ、Dispose実装でリソースを解放する限り、問題はありません。IDisposableインターフェイスの使用は、using()ステートメントを使用して実現することをお勧めします。これにより、オブジェクトがスコープ外になると、アプリはすぐにdisposeを呼び出します。すべて問題なく実行しているようです。その実装を使用するときは、必ずusing()を試して使用してください。

時々それが不可能で、スコープをもう少し長持ちさせたいことは知っていますが、使い捨ては通常、管理されていないリソースを操作するためのものであるため、これらのことにあまり寿命がない傾向があります

アップデート:

誰かがコメントに投稿したので、デストラクタを作成する理由もあるようです:)

あなたはここで毎日何か新しいことを学びます:D

于 2012-06-01T09:01:50.883 に答える
0

デストラクタではなくファイナライザを意味していると思います。

ファイナライザーは非常に珍しいことに注意してください。すべての使い捨てオブジェクトにファイナライザーが必要であるというのは、確かに正しくありません。通常、管理されていないリソース (つまり、CLR の制御外で取得されたもの) を制御するオブジェクトのみがファイナライザーを必要とする場合があります。

どうしてもファイナライザーが必要な場合はGC.SuppressFinanlize、dispose メソッドを呼び出す必要があります。メソッドを実装するDisposeためのドキュメントから:

Dispose メソッドは、破棄するオブジェクトの SuppressFinalize メソッドを呼び出す必要があります。オブジェクトが現在ファイナライズ キューにある場合、SuppressFinalize はその Finalize メソッドが呼び出されないようにします。Finalize メソッドを実行すると、パフォーマンスが低下することに注意してください。Dispose メソッドがオブジェクトをクリーンアップする作業を既に行っている場合、ガベージ コレクターがオブジェクトの Finalize メソッドを呼び出す必要はありません。

ファイナライザーを含むパターンの例については、GC.SuppressFinanlizeドキュメントを参照してください。

于 2012-06-01T09:04:08.590 に答える