【C#】なぜかイベントの削除ができない!-=演算子がどうしても効かない!→ラムダ式使ってない?

【C#】なぜかイベントの削除ができない!-=演算子がどうしても効かない!→ラムダ式使ってない?
スポンサーリンク

こんにちは。ゆとり(@yutori_techblog)です。

前にC#でハマったことがあったので紹介します。

なぜかイベントが削除できない!

C#ではイベントは+=演算子で追加し、-=演算子で削除しますが、なぜかイベントの削除ができなくてハマりました

そして数時間悩んだ末、原因は「ラムダ式」だとわかりました。
次のコードを見てください。

public partial class Form1 : Form {
    private int m_count = 0;

    public Form1 () {
        InitializeComponent ();
    }

    private void eventAdd_Button_Click (object sender, EventArgs e) {
        eventArea_Button.MouseEnter += (s, ee) => CountUp ();
    }

    private void eventRemove_Button_Click (object sender, EventArgs e) {
        eventArea_Button.MouseEnter -= (s, ee) => CountUp ();
    }

    private void CountUp () {
        label1.Text = (++m_count).ToString ();
    }
}

「イベント追加」ボタンでカウンタアップイベントを追加し、
「イベント削除」ボタンでカウンタアップイベントを削除しています。

まったく同じメソッドを追加・削除しているので、当然追加したイベントを削除できると思いましたが、実は削除できません!

イベントを削除しているはずなのにカウントアップされてしまう

これを回避するには、一旦デリゲート変数に格納してから、それを追加・削除しなければなりません。

public partial class Form1 : Form {
    private int m_count = 0;

    private EventHandler eventHandler;

    public Form1 () {
        InitializeComponent ();

        eventHandler = (s, e) => CountUp ();
    }

    private void eventAdd_Button_Click (object sender, EventArgs e) {
        eventArea_Button.MouseEnter += eventHandler;
    }

    private void eventRemove_Button_Click (object sender, EventArgs e) {
        eventArea_Button.MouseEnter -= eventHandler;
    }

    private void CountUp () {
        label1.Text = (++m_count).ToString ();
    }
}
イベントを正常に削除できるようになった

なんというめんどくささ…。
せっかくラムダ式でスッキリ書きたかったのに残念です。

ラムダ式が複数あると、中身が同じであっても、内部的には異なるメソッドと判定されるのでしょうか。
IL等が読めればその辺も解読できると思いますが、そこまでの知識がありませんのでここでご勘弁ください。

まとめ

  • ラムダ式を使ってイベントを追加すると、削除できなくなる!
  • イベントの削除がしたいときは面倒でもデリゲート変数を定義する!

以上です。