ファイナライザーは通常、管理されていないリソースを制御するために使用されることを私はよく知っています。ファイナライザーはどのような状況で管理対象のものを処理できますか?
私の理解では、ファイナライザキューに存在すると、オブジェクトまたはそれによって強く参照されるオブジェクトが収集されなくなりますが、(もちろん)ファイナライズからそれらを保護することはできません。通常のイベントでは、オブジェクトがファイナライズされると、そのオブジェクトはキューから削除され、参照するオブジェクトは次のGCパスで収集から保護されなくなります。ファイナライザーが呼び出されるまでに、オブジェクトによって参照されるオブジェクトの任意の組み合わせに対してファイナライザーが呼び出されている可能性があります。ファイナライザーが特定の順序で呼び出されることに依存することはできませんが、保持しているオブジェクト参照は引き続き有効である必要があります。
ファイナライザーがロックを取得したり、新しいオブジェクトを作成しようとしたりしてはならないことは明らかです。ただし、いくつかのイベントをサブスクライブするオブジェクトと、実際にイベントを使用する別のオブジェクトがあるとします。後者のオブジェクトがガベージコレクションの対象になった場合は、できるだけ早く前者のオブジェクトのイベントのサブスクライブを解除してもらいたいと思います。前者のオブジェクトは、ライブオブジェクトによってサブスクリプションが保持されなくなるまで、ファイナライズの対象になることはありません。
ロックフリーのリンクリストスタックまたはサブスクライブ解除する必要のあるオブジェクトのキューを用意し、メインオブジェクトのファイナライザーにスタック/キュー上の他のオブジェクトへの参照を配置させるのは実用的でしょうか?リンクリストアイテムオブジェクトは、メインオブジェクトの作成時に割り当てる必要があり(ファイナライザー内での割り当てが禁止されるため)、キューをポーリングするためにタイマーイベントなどを使用する必要があります(イベントのサブスクリプションが解除されるため)。ファイナライザースレッドの外部で実行する必要があり、ファイナライザーキューに何かが表示されるのを待つことだけを目的としたスレッドを作成するのはおそらくばかげていますが、ファイナライザーが事前に割り当てられたリンクリストオブジェクトを安全に参照できる場合そして、そのクラスに関連付けられたメインキューオブジェクト、
それは良い考えでしょうか?(注:私は.net 2.0を使用しています。また、スタックまたはキューに追加しようとすると、Threading.Interlocked.CompareExchangeで数回スピンする可能性がありますが、非常に長くスタックすることはないと思います)。
編集
確かに、イベントをサブスクライブするコードはiDisposableを実装する必要がありますが、使い捨てのものは常に適切に廃棄されるとは限りません。もしあれば、ファイナライザーは必要ありません。
私が懸念するシナリオは次のようなものです:iEnumerator(of T)を実装するクラスは、関連するクラスのchangeNotifyイベントにフックして、基になるクラスが変更された場合に列挙を適切に処理できるようにします(はい、Microsoftはすべての列挙型を考えています単にあきらめる必要がありますが、動作を継続できる列挙型の方が便利な場合もあります)。クラスのインスタンスは、数日または数週間の間に数千回または数百万回も列挙される可能性がありますが、その間はまったく更新されません。
理想的には、列挙子は破棄せずに忘れられることはありませんが、「foreach」と「using」が適用できないコンテキストで列挙子が使用されることがあります(たとえば、一部の列挙子はネストされた列挙をサポートします)。注意深く設計されたファイナライザーは、このシナリオに対処する手段を可能にするかもしれません。
ちなみに、更新を通じて継続することになっている列挙は、汎用のIEnumerable(of T)を使用する必要があります。iDisposableを処理しない非汎用フォームは、コレクションが変更された場合に例外をスローする必要があります。