今回はEventInfoを扱います。前回、MailServiceクラスにOnSendというイベント(Actionデリゲート)を作成したので、そのイベントをReflection経由で操作していきます。具体的には、イベントに対してハンドラー(呼び出されるメソッド)を登録する方法を確認します。
下準備:Assembly・Type・インスタンスの取得
いつも通り、まずはAssemblyからTypeを取得し、そこからインスタンスを生成しておきます。今回操作対象となるOnSendイベントは、MailServiceクラスに定義されています。
図1 MailServiceクラスに定義したOnSendイベント(public event Action OnSend;)
var a = Assembly.Load("Anderson.Domain");
var t = a.GetType("Anderson.Domain.MailService");
var instance = Activator.CreateInstance(t);
GetEventでEventInfoを取得する
イベント全体の一覧が欲しい場合は複数形のGetEventsを使います。特定の名前のイベントにピンポイントでアクセスしたい場合は、単数形のGetEventを使い、引数にイベント名を文字列で指定します。戻り値の型はEventInfoです。
図2 IntelliSenseに表示されるGetEventとGetEvents。単数形が1件取得、複数形が一覧取得
図3 t.GetEventの入力途中。戻り値がEventInfo?であることがツールチップで確認できる
今回は”OnSend”という名前のイベントを取得します。受け取る変数名は、後述するイベント引数のeと名前が被らないよう、eiとしておきます。
図4 EventInfo ei = t.GetEvent(“OnSend”); でOnSendイベントのEventInfoを取得
EventInfo ei = t.GetEvent("OnSend");
AddEventHandlerでハンドラーを登録する
取得したEventInfoに対してハンドラーを登録するメソッドがAddEventHandlerです。第1引数にはどのインスタンスに対して登録するか、第2引数にはどのメソッド(デリゲート)を登録するかを指定します。今回のOnSendはAction型(引数なし・戻り値なし)で作成しているので、登録するメソッドも引数なし・戻り値なしのものを用意します。
図5 ei.AddEventHandlerのIntelliSense。「Adds an event handler to an event source.」と説明されている
登録用のメソッドとして、private void AAA()を新たに作成します。中身はDebug.WriteLineで文字列を出力するだけの簡単な処理にしておきます。
図6 AddEventHandlerの第1引数にinstanceを指定し、登録用にprivate void AAA()を新規作成
図7 AAA()の中身。Debug.WriteLine(“aaa call!!!!”)で呼ばれたことが分かるようにする
最後にAddEventHandlerの第2引数にAAAを指定して、登録が完了します。
図8 ei.AddEventHandler(instance, AAA); でMailServiceのインスタンスにAAAを登録
ei.AddEventHandler(instance, AAA);
private void AAA()
{
Debug.WriteLine("aaa call!!!!");
}
Sendメソッドを呼び出して動作確認する
ハンドラーが登録されたかどうかを確認するには、OnSendを実際に呼び出す必要があります。OnSend自体はMailServiceのSendメソッドの中から呼ばれる作りになっているので、まずはSendメソッドをReflection経由で呼び出します。Sendはオーバーロードされているため、Type.EmptyTypesを指定して引数なしのSendを特定します。
図9 t.GetMethod(“Send”, Type.EmptyTypes); でオーバーロードのうち引数なしのSendを取得
取得したMethodInfoのInvokeを呼び出すことで、Sendメソッドが実行されます。Sendの中でOnSendがnullでなければInvokeされる作りになっているため、登録しておいたAAAが実行されるはずです。
図10 完成したコード全体。GetEvent→AddEventHandler→GetMethod→Invokeの一連の流れ
var m = t.GetMethod("Send", Type.EmptyTypes);
m.Invoke(instance, null);
実行してみると、出力ウィンドウにSend側の出力と、AAAの中のDebug.WriteLineによる「aaa call!!!!」が続けて表示されます。これにより、EventInfo経由で登録したハンドラーが正しく呼び出されていることが確認できます。
図11 実行結果。「send!!!!」に続けて「aaa call!!!!」が出力され、登録したAAAが動作したことが分かる
以上が、EventInfoを使ってイベントにハンドラーを登録する流れです。GetEventでピンポイントにEventInfoを取得し、AddEventHandlerで対象インスタンスとメソッドを紐付ける、という手順を覚えておいてください。
目次
はじめに
A01_はじめに
A02_コースの概要
Type
B01_Typeクラスとは
B02_型からTypeを取得する
B03_自前の型からTypeを取得する
B04_インスタンスからTypeを取得する
B05_Typeのインスタンスは1つだけ
Assembly
C01_Assemblyとは
C02_Assemblyの生成_実行中のアセンブリを取得
C03_Assemblyの生成_アセンブリ名で取得
C04_Assemblyの生成_パスを指定して取得
C05_Assemblyの生成_呼び出し元を取得
C06_Assemblyの生成_型から取得
C07_すべての型を取得する
C08_publicな型だけを取得する
C09_名前を指定して型を取得する
C10_メタ情報の取得
インスタンスの生成
D01_インスタンスの生成
D02_インスタンス生成後の具体例
D03_空のコンストラクタがないとエラーになる
D04_Activatorを使ったインスタンスの生成
D05_引数ありのコンストラクタで生成する方法
ConstructorInfo
E01_コンストラクタの情報を取得
E02_パラメータの情報を取得
E03_コンストラクタの情報からインスタンスを生成する
E04_コンストラクタを検索して生成する
E05_public以外のコンストラクタを取得
E06_staticなコンストラクタがある場合の注意点
E07_コンストラクタのアクセスレベルを取得する
MethodInfo
F01_MethodInfo
F02_引数ありのメソッド呼び出し
F03_メソッドがオーバーロードされているときの指定方法
F04_GetMethods
F05_属性で取得する
F06_staticメソッドを呼び出す
F07_戻り値を取得する
PropertyInfo
G01_PropertyInfo
G02_GetProperties
G03_属性を使ったチェック
G04_汎用的なチェックメソッド
G05_CanWrite
FieldInfo
H01_FieldInfo
H02_public以外のFieldInfo
EventInfo
J01_EventInfoとは
J02_AddEventHandler
J03_EventInfoの注意点
J04_RemoveEventHandler
dynamicを利用したリフレクション
K01_dynamicを利用したリフレクション
K02_dynamicを利用したメソッドの呼び方
K03_オーバーライドされたメソッドの呼び出し
K04_メソッドの存在チェック
K05_dynamicを利用したプロパティへのアクセス
K06_dynamicを利用したフィールドへのアクセス
K07_dynamicを利用したイベントへのアクセス