とある技術の開発日記

Diary of irregular phrase programmer

親クラスでPrivateなイベントハンドラを子クラスから削除する

仕事中に親クラスで定義されているイベントを無効化したかったのですが、
思った以上に苦労したため、備忘録として記事にする事にしました。

前提条件としては、親クラスのイベントハンドラのメソッド名が解っている事
この辺りはReflectionでも使用してうまく探し出しましょう。

まずは親クラス側のコード

using System;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
  public partial class BaseForm : Form
  {
    public BaseForm()
    {
      public TextBox textBox = new System.Windows.Forms.TextBox();
      this.textBox.KeyDown += new KeyEventHandler(this.textBox_KeyDown);
    }

    private void textBox_KeyDown(object sender, KeyEventArgs e)
    {
      MessageBox.Show("Base KeyDown");
    }
  }
}

テキストボックスにKeyDownイベントを設定します。

通常は以下のようにしてイベントハンドラの削除を行うのですが

this.textBox.KeyDown -= this.textBox_KeyDown;

この場合は、イベントハンドラはPrivateなので継承先からはアクセスできません。

そこでReflectionを使用してPrivateメソッドを取得して、イベントハンドラデリゲートに
ラップする事でイベントハンドラの削除を行います。

using System;
using System.Reflection;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
  public partial class ExtendForm : BaseForm
  {
    public ExtendForm()
    {
      var baseType = Type.GetType("WindowsFormsApplication1.BaseForm");
      var eventInfo = textBox.GetType().GetEvent("KeyDown");
      var handlerType = eventInfo.EventHandlerType;

      var eventMethodInfo = baseType.GetMethod("textBox_KeyDown", BindingFlags.NonPublic | BindingFlags.Instance);
      var eventMethod = System.Delegate.CreateDelegate(handlerType, this, eventMethodInfo);
      eventInfo.RemoveEventHandler(textBox, eventMethod);
    }
  }
}

System.Delegate.CreateDelegateメソッドでイベントハンドラデリゲートを作成する事ができます。
今回は削除する際に使用しましたが、同じような方法で動的に追加、削除が行えます。

本当はEventInfoクラスからメソッド名を使用せずにMethodInfoを取得したいのですが
上手くいきませんでした。
(EventInfo.GetRaiseMethodを利用してみたのですが上手くいかず・・・)

今までメタプログラミングやる機会がなかったのですが、
やってると何でもアリな感じが癖になって楽しいですw