Controlのイベントに動的に処理をアタッチする (解決!!!!)
匿名デリゲート(メソッド)はコンパイラが生成していたクラスなんだよってことは知っていたし、前のエントリにも書いたが、まさかそれ自体を、それも引数をGenericsにして生成してやることまでは考えなかった。驚きました。感服しました。これで数日悩んでいたことが全て吹っ飛びました。菊池さんに感謝。
菊池さんに書いていただいたサンプルコードを用いて全面的に処理を書き直しました。
public void AttachEvent(Form form, string controlName, string eventName, IAction action) { Control controls = form.Controls.Find(controlName, true); if (controls != null && controls.Length > 0) { foreach (Control control in controls) { EventInfo eventInfo = control.GetType().GetEvent(eventName); if (eventInfo != null) { /*デリゲートの戻り値を取得*/ Type returnType = GetDelegateReturnType(eventInfo.EventHandlerType); /*デリゲートのパラメタ型を取得*/ Type paramTypes = GetDelegateParameterTypes(eventInfo.EventHandlerType); /*匿名メソッド(デリゲート)の代替オブジェクトを生成*/ Type handlerType = typeof(EventHandler); handlerType = handlerType.GetGenericTypeDefinition(); Type handlerInstanceType = handlerType.MakeGenericType(paramTypes[1]); object pseudoAnnDelegate = handlerInstanceType.GetConstructor( new Type { typeof(IAction) }).Invoke(new object { action }); /*デリゲートを動的に生成してハンドラに追加*/ MethodInfo handlerMethod = handlerInstanceType.GetMethod("Handler"); eventInfo.AddEventHandler(control, Delegate.CreateDelegate(eventInfo.EventHandlerType, pseudoAnnDelegate, handlerMethod)); } } } } /*匿名メソッド(デリゲート)を代替して、EventArgsを汎用型としたインナクラス*/ class EventHandler where T : EventArgs { private IAction action; public EventHandler(IAction action) { this.action = action; } public void Handler(object sender, T e) { action.Run(); } } private Type GetDelegateParameterTypes(Type delegateType) { MethodInfo invoke = delegateType.GetMethod("Invoke"); ParameterInfo parameters = invoke.GetParameters(); Type[] typeParameters = new Type[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { typeParameters[i] = parameters[i].ParameterType; } return typeParameters; } private Type GetDelegateReturnType(Type delegateType) { MethodInfo invoke = delegateType.GetMethod("Invoke"); return invoke.ReturnType; }
実際組み込んでテストもしてみたが、完璧。何をやりたかったのかは、別なエントリで改めて。
追記:
堂々巡りをしていたのは、やはりType::MakeGenericTypeの存在を知らなかった勉強不足に尽きる。
MSIL周りに固執して勉強したのはどこかで役に立つと信じよう。