イベント ハンドラーにデリゲートを追加するときはいつでも、後でそれを削除する必要がありますよね?
まあ、いつもではありません。追加するイベント ハンドラーを削除する理由は 2 つあります。
- 同じインスタンスに短命のハンドラーを常に追加しています。それらを削除しなかった場合、ほとんどのハンドラーが不要になったときに、ますます多くのハンドラーが追加されます。
- ハンドラーは、イベントが属するオブジェクトのライフタイムよりもはるかに短いライフタイムのオブジェクトへの参照を内部的に保持しており、他のオブジェクトがスコープ外になると、イベント ハンドラーは呼び出されません (または呼び出されません)。 . イベント ハンドラーをアタッチしたままにしておくと、イベント ハンドラーが必要以上に長くメモリ内にとどまるか、「古くなった」オブジェクトを使用してしまう可能性があり、もう使用すべきではありません。(たとえば、リソースが既に破棄されている場合は、そのイベントをもう発生させたくないでしょう。)
#2 が問題である理由は、ガベージ コレクションが C# でどのように機能するかによるものです。スコープ内に 100% 確実に存在するすべてのオブジェクトを「生きている」とマークし、すべての生きているオブジェクトのすべての参照を追跡するまで、それらの「生きている」オブジェクトのいずれかが「生きている」として参照するすべてのものを追跡します。「生きている」とマークされなかったものはすべて「死んでいる」と見なされ、ガベージ コレクションの対象となります。
イベントにアタッチされたイベント ハンドラーがある場合、デリゲートには、オブジェクトのインスタンスとそのオブジェクトで実行するメソッドの 2 つが含まれます。その参照されたオブジェクトは、次のいずれかになるまでガベージ コレクションできません。
- イベントが発生したオブジェクトは、もはや「生きていません」。
- イベント ハンドラー (つまり、デリゲートへの参照) を削除して、オブジェクトを早期に解放できるようにします。
とはいえ、かなりの割合のケースがこれらのいずれにも当てはまらないため、わざわざイベント ハンドラーを削除する必要はありません。
例として、イベント オブジェクトが範囲外になる直前にイベント ハンドラーを削除する人をよく見かけます。それは無意味です。オブジェクトが範囲外にある場合、参照を保持しても問題はありません...何でも。
ここで、イベント ハンドラーのサブスクライブを解除する必要がある数少ない状況の 1 つで、匿名メソッドを使用している場合は、そうする必要はありません。名前付きメソッドにすることができるクラスを作成し、それを使用するだけです。