How to dynamically subscribe to an event?
RELATED
- Watch control to determine events being fired?
I need to detect when an event is fired. To do so I am trying to subscribe dynamically on the event.
The problem is that I have different开发者_StackOverflow中文版 types of delegates, not all events have the same signature. The solutions provided in here and here expects object sender, EventArgs e
, which I am not using, so I get an exception telling the types doesn't match.
Here are some examples of a delegates I have:
public delegate void OnEventA(int id);
public delegate void OnEventB(double num, string name);
How can I create the correct delegate?
EventInfo
has a method AddEventHandler
that you can use. If you don't have a delegate instance, then you can create a delegate dynamically using Delegate.CreateDelegate
:
var eh = Delegate.CreateDelegate(ei.EventHandlerType, target, methodInfo);
ei.AddEventHandler(owner, eh);
In this example target
is the target object for the delegate and methodInfo
is a MethodInfo
of a method in the target
object. Finally, owner
is the object where the event ei
belongs.
After some research I found some articles:
- How to: Hook Up a Delegate Using Reflection
- Delegate.CreateDelegate Method (Type, Object, MethodInfo, Boolean)
It helped me to understand what I was trying to do and I should do.
I need to use Delegate.CreateDelegate
passing the EventHandlerType
(the type of the event, the delegate), a instance of a class and the method info of the method (from the class in the previous parameter) that will handle the event. Target is the control that fires this event.
Delegate handler = Delegate.CreateDelegate(evt.EventHandlerType, abc, mi1, false);
evt.AddEventHandler(target, handler);
Further digging lead me to this method. I can subscribe to events using lambda expression. Using Action<T>
I can subscribe with different types and numbers of parameters.
public static Delegate Create<T>(EventInfo e, Action<T> a)
{
var parameters = e.EventHandlerType.GetMethod("Invoke").GetParameters().Select(p => Expression.Parameter(p.ParameterType, "p")).ToArray();
var exp = Expression.Call(Expression.Constant(a), a.GetType().GetMethod("Invoke"), parameters);
var l = Expression.Lambda(exp, parameters);
return Delegate.CreateDelegate(e.EventHandlerType, l.Compile(), "Invoke", false);
}
Using this method (e is the EventInfo; EventManager is the class with the static method above)
e.AddEventHandler(this, EventManager.Create<int>(e, (x) => Console.WriteLine("Execute")));
精彩评论