[C#][dynamic] 動的にイベント ハンドラーを追加
今回は、動的にイベント ハンドラーの追加を行ってみたい。
■ 動的に読み込まれるクラス ライブラリー側
例えば、次のようなクラス ライブラリー (ClassLibrary.dll) があるとする。
// クラス ライブラリー側: ClassLibrary.dll namespace ClassLibrary { public class Data : IEnumerable<string> { // 更新されると起きるイベント public event EventHandler Update; List<string> itemList = new List<string>(); // アイテムの追加 public void Add(string item) { itemList.Add(item); // 更新イベントを起こす if (Update != null) Update(this, null); } // IEnumerable<string> の実装 public IEnumerator<string> GetEnumerator() { return itemList.GetEnumerator(); } // IEnumerable<string> の実装 IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } }
クラス Data は、文字列のコンテナー クラスで、文字列が追加 (Add) されると、Update イベントが起きるようになっている。
■ クラス ライブラリーを動的に読み込む側
別のプロジェクトで、このクラス ライブラリーを動的に読み込んで使いたいとする。
こちらでは、先ず先の Data を表示するための View クラスを用意することにする。
・View クラス
using System; using System.Collections.Generic; class View { public IEnumerable<string> DataSource { private get; set; } // Update のイベント ハンドラー用 public void OnUpdate(object sender, EventArgs e) { Show(); } // DataSource の内容を表示 void Show() { Console.WriteLine("View:"); if (DataSource == null) return; foreach (var item in DataSource) Console.WriteLine("\t{0}", item); } }
表示したい IEnumerable<string> な DataSource を予め設定しておくと、OnUpdate が呼ばれたときにそれを表示する、というクラスだ。
・動的にイベント ハンドラーを設定
それでは、クラス ライブラリーを動的に読み込み、その中の Data クラスのインスタンスを生成し、それにイベント ハンドラーを追加してみよう。
クラス ライブラリーを動的に読み込み、その中の Data クラスのインスタンスを生成
using System; using System.Collections.Generic; using System.Reflection; class Program { static void Main() { // アセンブリ名を使ってクラス ライブラリーを動的に読み込み Assembly assembly = Assembly.Load("ClassLibrary"); // アセンブリ内のクラス Data の型情報を取得 Type dataType = assembly.GetType("ClassLibrary.Data"); // アセンブリ内のクラス Data のインスタンスを生成 var data = Activator.CreateInstance(dataType); } }
続いて、View のインスタンスを生成して DataSource に data を設定
// ...省略... class Program { static void Main() { // ...省略... // View のインスタンスを生成して DataSource に data を設定 var view = new View { DataSource = data as IEnumerable<string> }; } }
次に、イベント ハンドラー view.OnUpdate からデリゲートを作成し、それを動的にイベント ハンドラーとして追加
// ...省略... class Program { static void Main() { // ...省略... // Delegate クラスを利用してイベント ハンドラーである view.OnUpdate からデリゲートを作成 Delegate eventHandlerDelegate = Delegate.CreateDelegate(typeof(EventHandler), view, "OnUpdate"); // アセンブリ内のクラスの Update イベントの EventInfo を取得 EventInfo eventInfo = dataType.GetEvent("Update"); // EventInfo に対してイベント ハンドラーを追加 eventInfo.AddEventHandler(data, eventHandlerDelegate); } }
・試してみる
では試してみよう。
data に対して、文字列を追加 (Add) する度に view.OnUpdate が呼ばれれば OK だ。
// ...省略... class Program { static void Main() { // ...省略... // data.Add("Apple"); を動的に呼び出す dataType.InvokeMember("Add", BindingFlags.InvokeMethod, null, data, new object[] { "Apple" }); // data.Add("Banana"); を動的に呼び出す dataType.InvokeMember("Add", BindingFlags.InvokeMethod, null, data, new object[] { "Banana" }); } }
結果コンソールには、次のように表示される。
View: Apple View: Apple Banana
文字列を追加 (Add) する度にイベント ハンドラー view.OnUpdate が呼ばれているのが判る。
ディスカッション
コメント一覧
まだ、コメントがありません