web-dev-qa-db-ja.com

Disposeメソッドでイベントハンドラーを常に切断する必要がありますか?

私はC#で働いており、職場にはいくつかのコード標準があります。その1つは、接続する各イベントハンドラー(KeyDownなど)をDisposeメソッドで切断する必要があることです。その理由はありますか?

40

イベントのパブリッシャーがサブスクライバーより長生きすることを期待しない限り、イベントハンドラーを削除する理由はありません。

これは、民間伝承が成長したトピックの1つです。あなたは本当にそれを通常の用語で考える必要があります:出版社(例えばボタン)は購読者への参照を持っています。パブリッシャーとサブスクライバーの両方がガベージコレクションの対象となる場合(一般的な場合)、またはパブリッシャーがガベージコレクションの対象となる場合以前の場合、GCの問題はありません。

静的イベントは、実質的に無期限の発行者であるため、GCの問題を引き起こします-可能であれば、静的イベントを完全に阻止します。 (私はそれらが有用であることをめったに見つけません。)

もう1つの考えられる問題は、イベントが発生するとオブジェクトが誤動作するため、明示的にイベントのリッスンを停止したい場合です(たとえば、閉じたストリームへの書き込みを試みます)。その場合、はい、ハンドラーを削除する必要があります。これは、クラスが既にIDisposableを実装している場合に最もよく起こります。不可能ではありませんが、IDisposablejustを実装してイベントハンドラを削除する価値があるのは珍しいことです。

71
Jon Skeet

動的に作成および破棄されているユーザーコントロールのDispose()でイベントハンドラーの登録を解除しなかった場合、アプリケーションでメジャーGDIリークが発生しました。 Visual Studio 2013ヘルプ(C#プログラミングガイド):イタリック体で示したものに注意してください。

方法:イベントの購読と購読解除

... snip ... nsubscribingイベントが発生したときにイベントハンドラーが呼び出されないようにするには、イベントからサブスクライブを解除します。 リソースリークを防ぐために、サブスクライバーオブジェクトを破棄する前にイベントのサブスクリプションを解除する必要があります。イベントのサブスクリプションを解除するまで、パブリッシングオブジェクトのイベントの基になるマルチキャストデリゲートには、サブスクライバのイベントハンドラをカプセル化するデリゲートへの参照があります。発行オブジェクトがその参照を保持している限り、ガベージコレクションはサブスクライバオブジェクトを削除しません。

私の場合、パブリッシャーとサブスクライバーの両方が同じクラスにあり、ハンドラーは静的ではないことに注意してください。

11
JonP