私は C# で作業しており、職場にはいくつかのコード標準があります。そのうちの 1 つは、接続する各イベント ハンドラー ( などKeyDown
) をメソッド内で切断する必要があることDispose
です。それには正当な理由がありますか?
4 に答える
イベントのパブリッシャーがサブスクライバーよりも長生きすると予想しない限り、イベント ハンドラーを削除する理由はありません。
これは、民間伝承が育ったトピックの 1 つです。通常の用語で考える必要があるだけです。パブリッシャー (ボタンなど) は、サブスクライバーへの参照を持っています。パブリッシャーとサブスクライバーの両方が同時にガベージ コレクションの対象となる場合 (よくあることですが)、またはパブリッシャーが以前にガベージ コレクションの対象となる場合、GC の問題はありません。
静的イベントは事実上無限に存続するパブリッシャーであるため、GC の問題を引き起こします。可能であれば、静的イベントを完全に思いとどまらせます。(私はそれらが役に立つとはほとんど思いません。)
もう1つの考えられる問題は、イベントが発生するとオブジェクトが誤動作するため、イベントのリッスンを明示的に停止したい場合です(たとえば、閉じたストリームに書き込もうとするなど)。その場合、はい、ハンドラーを削除する必要があります。IDisposable
これは、クラスが既に実装されている場合に発生する可能性が最も高いです。イベント ハンドラーを削除するためIDisposable
だけに実装する価値があるのは、不可能ではありませんが、珍しいことです。
動的に作成および破棄されるユーザー コントロールの Dispose() でイベント ハンドラーを登録解除しなかった場合、アプリケーションで重大な GDI リークが発生しました。C# プログラミング ガイドの Visual Studio 2013 ヘルプで次の情報を見つけました。イタリック体で記載した内容に注意してください。
方法: イベントをサブスクライブおよびサブスクライブ解除する
...をちょきちょきと切る... 購読解除 イベントが発生したときにイベント ハンドラーが呼び出されないようにするには、イベントのサブスクライブを解除します。リソース リークを防ぐために、サブスクライバー オブジェクトを破棄する前に、イベントからサブスクライブを解除する必要があります。イベントのサブスクライブを解除するまで、発行オブジェクトのイベントの基になるマルチキャスト デリゲートは、サブスクライバーのイベント ハンドラーをカプセル化するデリゲートへの参照を保持します。パブリッシング オブジェクトがその参照を保持している限り、ガベージ コレクションはサブスクライバー オブジェクトを削除しません。
私の場合、パブリッシャーとサブスクライバーの両方が同じクラスにあり、ハンドラーは静的ではないことに注意してください。