4

クラスに Finalize と Dispose を実装していました。親クラスに IDisposable を実装し、子クラスの Dispose(bool) オーバーロードをオーバーライドしました。よくわかりませんでした

  1. 重複する isDisposed 変数を使用するかどうか (基本クラスに既に存在するため) かどうか?
  2. 子クラスにもファイナライザを実装するかどうか

これらは両方とも、ここに示す例で行われます-

http://guides.brucejmack.biz/CodeRules/FxCop/Docs/Rules/Usage/DisposeMethodsShouldCallBaseClassDispose.html

このMSDNの記事の例には、これら2つのいずれもありません - http://msdn.microsoft.com/en-us/library/b1yfkh5e.aspx

一方、MSDN のこの例は完全ではありません - http://msdn.microsoft.com/en-us/library/ms182330.aspx

4

5 に答える 5

6

ファイナライザーが役立つことは非常にまれです。リンク先のドキュメントは完全に役立つわけではありません。次のかなり循環的なアドバイスを提供しています。

ファイナライズが必要なオブジェクトにのみ Finalize を実装する

これは質問をする良い例ですが、あまり役に立ちません。

実際には、ほとんどの場合、ファイナライザーは必要ありません。(.NET 開発者が経験しなければならない学習曲線の 1 つは、ファイナライザーが必要だと考えているほとんどの場所で、ファイナライザーが必要ないことを発見することです。) これを (とりわけ) WPF の質問としてタグ付けしました。ほとんどの場合、UI オブジェクトにファイナライザーを配置するのは間違いです。(したがって、ファイナライザーが必要であることが判明した異常な状況の 1 つにいる場合でも、その作業は、WPF に関係するコードの近くには属しません。)

ファイナライザーが役立つ可能性があると思われるほとんどのシナリオでは、実際にはそうではありません。ファイナライザーが実行されるまでには、有用なことを行うにはすでに遅すぎるためです。

たとえば、ファイナライザーが実行されるまでに、それらのオブジェクトはすでにファイナライズされている可能性があるため、オブジェクトが参照しているオブジェクトに対して何かをしようとするのは、通常は悪い考えです。(.NET は、ファイナライザーが実行される順序について保証しないため、参照先のオブジェクトがファイナライズされているかどうかを知る方法がありません。) ファイナライザーが既に実行されているオブジェクトでメソッドを呼び出すのは悪い考えです実行されました。

一部のオブジェクトが確実にファイナライズされていないことを知る方法がある場合は、それを使用しても安全ですが、それは非常に珍しい状況です (...問題のオブジェクトにファイナライザーがなく、ファイナライズ可能なリソース自体を使用しません.しかし、その場合、あなた自身のオブジェクトがなくなったときに実際に何かをする必要があるオブジェクトではないでしょう.)

ファイナライザーが役立つと思われる主な状況は相互運用です。たとえば、P/Invoke を使用してアンマネージ API を呼び出し、その API がハンドルを返すとします。おそらく、そのハンドルを閉じるために呼び出す必要がある他の A​​PI があるでしょう。それはすべて管理されていないものであるため、.NET GC はそれらのハンドルが何であるかを知りません。それらが確実にクリーンアップされるようにするのはあなたの仕事です。SafeHandleそのシナリオに を使用します。

実際には、ファイナライザーを使用していることに気付いた唯一の場所は、a) GC の機能を調査するために設計された実験、および b) 特定のオブジェクトがシステムでどのように使用されているかについて何かを発見するために設計された診断コードです。どちらの種類のコードも最終的に本番環境に入るべきではありません。

したがって、「子クラスにもファイナライザーを実装する必要があるかどうか」に対する答えは、次のとおりです。尋ねる必要がある場合、答えはノーです。

フラグを複製するかどうかについては...他の回答がここで矛盾したアドバイスを提供しています。主なポイントは、1) ベースを呼び出す必要があること、Disposeおよび 2)Disposeべき等である必要があることです。(つまり、1 回、2 回、5 回、100 回呼び出されても問題ありません。2 回以上呼び出されても文句を言うべきではありません。)好きなように実装するのは自由です。ブール値のフラグは1つの方法ですがnull、メソッドで特定のフィールドを に設定するだけで十分であることがよくあります。そのDispose時点で、別のブール値フラグの必要性がなくなりDisposeますnull

そこにあるガイダンスの多くはIDisposable、ファイナライザーが必要な状況に対処しているため、非常に役に立ちませんが、実際には非常にまれなケースです。IDisposableこれは、多くの人が必要以上に複雑な実装を書いていることを意味します。実際には、ほとんどのクラスは、jpierson がリンクしている記事で、 Stephen Cleary が「レベル 1」と呼んでいるカテゴリを呼び出します。これらについては、ほとんどの例をごちゃごちゃにしているGC.KeepAliveGC.SuppressFinalize、およびすべてのものは必要ありません。Dispose(bool)これらの「レベル 1」タイプに対する Cleary のアドバイスが示すように、人生はほとんどの場合、実際にははるかに単純です。

于 2010-12-14T13:08:00.067 に答える
2

重複が必要です

子クラスにクリーンアップがない場合は、単に を呼び出します。base.Dispose()クラス レベルのクリーンアップがある場合は、 への呼び出しの後に実行しますbase.Dispose()。これら 2 つのクラスの状態を分離する必要があるIsDisposedため、各クラスにブール値が必要です。このようにして、必要なときにいつでもクリーンアップ コードを追加できます。

クラスを と判断した場合は、私がそのクリーンアップ手順を担当していることをIDisposable伝えるだけで、このクラスを使用する必要があるため、キューから削除します。呼び出さない限り、クラスにとって特別なことは何も起こりません。したがって、私が述べたように実装する場合、ファイナライズしないように言ったので、必要はありません。GCSuppressFinilizeGCGC.SupressFinalize(this)IDisposableFinilizerGC

于 2010-12-14T12:40:59.777 に答える
1

IDisposable を実装する正しい方法は、クラスが所有するアンマネージ リソースがあるかどうかによって異なります。IDisposable を実装する正確な方法については、まだすべての開発者が同意しているわけではなく、Stephen Clearyのような一部の開発者は、使い捨てパラダイム全般について強い意見を持っています。

参照:アンマネージ リソースをクリーンアップするための Finalize と Dispose の実装

IDisposable インターフェイスのドキュメントでもこれについて簡単に説明されており、この記事では同じことのいくつかを指摘していますが、MSDN についても指摘しています。

基本クラスで重複するブールフィールド「isDisposed」が必要かどうかについて。これは主に、サブクラス自体が破棄する必要のある追加のアンマネージ リソースを追加する可能性がある場合に使用できる便利な規則にすぎないようです。Dispose は仮想として宣言されているため、サブクラスのインスタンスで Dispose を呼び出すと、常にそのクラスの Dispose メソッドが最初に呼び出され、継承階層の各レベルをクリアする機会を与える最後のステップとして base.Dispose が呼び出されます。したがって、サブクラスにベースが所有するものの上に追加の管理されていないリソースがある場合、おそらく独自のブール値の isDisposed フィールドを使用して、その Dispose メソッド内のトランザクションの性質でその処分を追跡するのが最善であると要約しますが、Ian として彼の答えで言及している、

于 2010-12-14T12:42:28.730 に答える
0

オブジェクトがクリーンアップが必要なものに関する情報を保持し、この情報がクリーンアップが必要な他のオブジェクトへのオブジェクト参照以外の形式である場合にのみ、ファイナライザーを実装します (たとえば、Int32 として格納されたファイルハンドル)。クラスがファイナライザーを実装する場合、クリーンアップに不要な他のオブジェクトへの強いオブジェクト参照を保持しないでください。他の参照を保持する場合、クリーンアップを担当する部分は、ファイナライザーを使用して独自のオブジェクトに分割する必要があり、メイン オブジェクトはそれへの参照を保持する必要があります。その場合、メイン オブジェクトにはファイナライザーがありません。

派生クラスは、基本クラスの目的がファイナライザーをサポートすることである場合にのみ、ファイナライザーを持つ必要があります。クラスの目的がファイナライザーに集中していない場合、派生クラスがファイナライザーを追加できるようにしてもあまり意味がありません。独自のクラスであり、それへの参照を保持するだけです)。

于 2010-12-14T15:54:26.913 に答える
0

1) 複製する必要はありません

2) ファイナライザーを実装すると、明示的に破棄されていないアイテムを破棄するのに役立ちます。しかし、保証されていません。これは良い習慣です。

于 2010-12-14T12:21:18.713 に答える