none
イベントハンドラーの設定で、+= new がある行を設定しますが、-= newの行 は省略しても構いませんか? RRS feed

  • 質問

  • 自分で、イベントハンドラーを設定する場合に、最初に、例えば、
    this.cBgWorker.DoWork += new System.ComponentModel.DoWorkEventHandler(this.cBgWorker_DoWork); 
    と入れています。終わる時に、
    this.cBgWorker.DoWork -= new System.ComponentModel.DoWorkEventHandler(this.cBgWorker_DoWork); 
    とも入れています。

    昔、勉強した時に、ガベージコレクションで要らないともありましたが、
    何処かで、要るともありましたので、 念のために -= new を含む行を気を使って入れています。

    フォームにコントロールを追加し、イベントを追加した場合には、
    xxx.Designer.cs ファイルには += new を含む行だけしかありません。

    抜けが無いように気を使て -= new を含む行を要れる必要は無さそうでもあります。
    本当はどうなんですか?

    mnicksashimisan

    2017年8月24日 1:53

回答

  • イベントハンドラを登録するというのは、イベントを提供するオブジェクトが、イベントハンドラを実装するオブジェクトの参照を持つということです。参照を握られてしまうので、イベントハンドラを実装するオブジェクトはその使用が終わっても、ガベージコレクションで回収されなくなります。いわゆるメモリーリークです。
    これを避けるために「弱い参照」の仕組みが用いられたりします。

    フォームとコントロールの場合、寿命は同じなので上記を気にする必要がありません。つまり、フォームだけ先に寿命が終わり、コントロールがイベントハンドラを掴み続けたまま生き続け、ガベージコレクションに回収されなくなることはありません。よって、わざわざイベントハンドラを解除する必要がないのです。

    イベントハンドラの登録とは、イベントハンドラを実装するオブジェクトの参照を持つということに注意し、イベントを提供する側、およびイベントハンドラを提供する側の寿命を考え、イベントハンドラを実装するオブジェクトの寿命が先に無くなる場合は、イベントハンドラの解除をしたり、弱い参照を使うようにして下さい。


    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    2017年8月24日 2:37
    モデレータ
  • > 抜けが無いように気を使て -= new を含む行を要れる必要は無さそうでもあります。

    静的イベント(例: Application クラスのイベント)の場合は、アプリケーションが破棄されるときにイベントハンドラーをデタッチしないと、メモリリークが発生するそうです。

    Application クラス
    https://msdn.microsoft.com/ja-jp/library/system.windows.forms.application(v=vs.110).aspx

    2017年8月24日 2:34

すべての返信

  • > 抜けが無いように気を使て -= new を含む行を要れる必要は無さそうでもあります。

    静的イベント(例: Application クラスのイベント)の場合は、アプリケーションが破棄されるときにイベントハンドラーをデタッチしないと、メモリリークが発生するそうです。

    Application クラス
    https://msdn.microsoft.com/ja-jp/library/system.windows.forms.application(v=vs.110).aspx

    2017年8月24日 2:34
  • イベントハンドラを登録するというのは、イベントを提供するオブジェクトが、イベントハンドラを実装するオブジェクトの参照を持つということです。参照を握られてしまうので、イベントハンドラを実装するオブジェクトはその使用が終わっても、ガベージコレクションで回収されなくなります。いわゆるメモリーリークです。
    これを避けるために「弱い参照」の仕組みが用いられたりします。

    フォームとコントロールの場合、寿命は同じなので上記を気にする必要がありません。つまり、フォームだけ先に寿命が終わり、コントロールがイベントハンドラを掴み続けたまま生き続け、ガベージコレクションに回収されなくなることはありません。よって、わざわざイベントハンドラを解除する必要がないのです。

    イベントハンドラの登録とは、イベントハンドラを実装するオブジェクトの参照を持つということに注意し、イベントを提供する側、およびイベントハンドラを提供する側の寿命を考え、イベントハンドラを実装するオブジェクトの寿命が先に無くなる場合は、イベントハンドラの解除をしたり、弱い参照を使うようにして下さい。


    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    2017年8月24日 2:37
    モデレータ
  • 私がやったことのある登録は静的イベントでもなく、
    フォーム上のコントロールのイベントだけで、イベントハンドラの解除は必要なかったようです。
    ありがとうございました。

    mnicksashimisan

    2017年8月24日 6:20
  • 私がやったことのある登録は静的イベントでもなく、
    フォーム上のコントロールのイベントだけで、イベントハンドラの解除は必要なかったようです。
    ありがとうございました。

    mnicksashimisan

    イベントハンドラのリークの問題よりも、ハンドラとオブジェクトの寿命というかインスタンスの関係が固定なのかで考えるほうがよいです。

    ※ハンドラをどのタイミングで登録しているか、に関係する

    this.cBgWorkerということは、これはメンバとして保持しているコントロールですよね?
    おそらく寿命はフォームと同じでしょう。

    ではハンドラを登録しているのはどこでしょうか?もしフォームの初期化時などに一度だけということであれば、登録の解除は必要ありません。
    フォームの寿命で自動的に解除される動作に任せて問題ないためです。

    もしバックグラウンド処理を開始するタイミングで、毎回ハンドラを登録しているのであれば、当然使い終わったら登録を解除する必要があります。でないと登録されるハンドラがどんどん増えていきます。

    ※おそらくこんなことはしていないと思いますが。

    ついでに静的イベントの場合はメモリリークするという話ですが、これはイベントハンドラ側のオブジェクトが、イベント登録解除するまでGCで回収されない、という問題です。

    よって、Applicationの静的イベントなど、そもそもアプリ実行中にずっと有効であってほしいイベントハンドラであれば解除は不要です。
    アプリケーション終了時にメモリリークするということはありません。

    アプリケーション終了前に、イベントハンドラ側を削除したいという場合に限り、要するにイベントハンドラの有効期間がアプリケーション本体よりも短い場合は、冬尾になった段階で削除しないと、ハンドラ側が残り続けることになります。

    アプリケーションの破棄が何を意味しているかは分かりませんが、普通はアプリケーション終了時に破棄?されるものですので、普通のアプリケーションでは解除は不要です。

    2017年8月24日 6:59
  • this.cBgWorkerは、メンバとして保持しているコントロールです。
    ハンドラを登録しているのはフォームの初期化時の一度だけです。

    > アプリケーションの破棄が何を意味しているかは分かりませんが、
    > 普通はアプリケーション終了時に破棄?されるものですので、
    > 普通のアプリケーションでは解除は不要です。
    Applicationの静的イベントに関しては、私はやっていませんし、少し難しい話のようです。
    よろしければ、どなたか議論してください。



    mnicksashimisan

    2017年8月25日 0:57