EventInfoクラスには、直接イベントを発行するメソッドは用意されていません。 そのためイベント発行時の動作と同等の処理を独自に記述する必要があります。 EventInfoクラスからは以下のような手順をとることでイベントの発行を行うことができます。
- イベントハンドラのデリゲートを格納しているフィールドのFieldInfoを取得する
- 取得したFieldInfoからイベントハンドラを格納しているMulticastDelegateを取得する
- MulticastDelegate.GetInvocationListメソッドを使ってイベントハンドラとして割り当てられているメソッドのリスト(MethodInfoの配列)を取得する
- 取得したMethodInfoひとつずつに対してメソッドの呼び出しを行う
C#とVBではイベントハンドラを格納しているフィールド名が異なる点に注意が必要です。 例えばイベント名がClick
の場合、C#ではフィールドClick
、VBではフィールドClickEvent
にイベントハンドラが格納されます。
上記の処理を具体的に実装すると次のようになります。
EventInfoを使ってイベントの発行を行う
using System;
using System.Reflection;
class C {
public event EventHandler<EventArgs> E;
}
class Sample {
static void Handler1(object sender, EventArgs e)
{
Console.WriteLine("Handler1");
}
static void Handler2(object sender, EventArgs e)
{
Console.WriteLine("Handler2");
}
static void Main()
{
var inst = new C();
// イベントEにハンドラを割り当てる
inst.E += Handler1;
inst.E += Handler2;
// イベントEのEventInfoを取得する
var ev = inst.GetType().GetEvent("E");
// EventInfoを使ってイベントを発行する
Raise(inst, ev, EventArgs.Empty);
}
static void Raise<TEventArgs>(object sender, EventInfo ev, TEventArgs e)
{
var f = sender.GetType().GetField(ev.Name, BindingFlags.Instance | BindingFlags.NonPublic);
var handler = (MulticastDelegate)f.GetValue(sender);
if (handler == null)
return;
foreach (var h in handler.GetInvocationList()) {
h.Method.Invoke(h.Target, new object[] {sender, e});
}
}
}
実行結果
Handler1 Handler2
MulticastDelegate.GetInvocationListメソッドについてはデリゲートの機能 §.呼び出されるメソッド・インスタンスの取得 (Method, Target, GetInvocationList)で解説しています。