INotifyPropertyChanged のコンシューマーが、特定の INotifyPropertyChanged オブジェクトの有効期間中にコンシューマーの任意の数のインスタンスが作成される可能性がある状況でも、そのオブジェクトのプロパティが変更されずにメモリ リークを回避できるパターンはありますか?通知の発火)?イベント パブリッシャーがリフレクションの策略を使って弱いイベントを実装することは可能です。実行可能なサブスクライバー側の弱いイベント パターンはありますか?
イベント コントラクトで、イベント サブスクライバーが無期限にブロックすることなく、いつでも任意のスレッドからサブスクライブ解除できるようにする必要がある場合、イベント サブスクライバーは、サブスクライバーに実際に「関心のある」オブジェクトを保持することができます。ラッパー オブジェクトへの参照を作成し、ラッパー オブジェクトで Finalize() をオーバーライドして、サブスクライバー オブジェクトにサブスクライブを解除するように指示します。残念ながら、サブスクライバーが Finalize() を介してサブスクリプションをキャンセルする必要があることを発見した場合でも、.net イベント コントラクトでは、イベントを発行するオブジェクトをファイナライザー内から安全に破棄できるようにする必要はありません。実際、C# の既定のイベント実装は、ファイナライザー内から呼び出すのは安全ではありません (現在の実装は、サブスクリプションを発行するオブジェクトのロックを取得します。ロックがサブスクリプションとサブスクリプション解除にのみ使用される場合は問題ありませんが、ロックが他の目的で任意の期間保持されないという保証はありません)。以前の実装はもっと悪かった: クラスがそれ自体のイベントを購読または購読解除しようとした場合、購読と購読解除はまったくスレッドセーフではありませんでした。
INotifyPropertyChanged オブジェクトが、そのイベントをスレッド セーフな方法で実装した特定のクラスであることがわかっている場合 (サブスクリプションの場合は、ロックを取得してから Interlocked.Exchange スピン ループを使用します。サブスクリプション解除の場合は、スピン ループを使用して、利用可能な場合はロックしますが、ロックが利用可能かどうかに関係なく Interlocked.CompareExchange を試行します) ファイナライザーでイベント ハンドラーを安全に削除できます。オブジェクトがかなりの頻度でイベントを発生させることがわかっている場合は、おそらくイベント内からハンドラーを削除できます (ただし、.net イベント コントラクトで安全である必要があるかどうかはわかりません)。監視する INotifyPropertyChanged 実装者のタイプに関係なく機能する汎用ソリューションはありますか?
編集 -- 明確化
オブジェクトがそれ自体のファイナライザーからサブスクライブを解除するという考えではなく、イベントの効果に関心のあるオブジェクトが、イベント処理自体が参照を保持しないラッパー オブジェクトへの参照を保持するということです。たとえば、特定のイベント名文字列で PropertyChanged イベントが発生した回数をカウントすることが目標であるとします。PropertyChangeCounter.Internals オブジェクトへの参照を保持する PropertyChangeCounter オブジェクトを持つことができます。後者のオブジェクトは、イベント サブスクリプションと変更カウントを保持します。PropertyChangeCounter オブジェクトの ChangeCount プロパティは、ネストされた PropertyChangeCounter.Internals ChangeCount の値を返します。ラッパーオブジェクトは、部外者がそれへの参照を保持しなくなると、ファイナライズの対象になります。