I have a WPF control with very poor documentation.
In the codebehind I’d like to reflect over the events that the control fires using GetType().GetEVents() and add a handler to each one which simply prints out the name of the event.
This would allow me to see what interacting with the control is actually doing.
So far I have:
foreach (var e in GetType().GetEvents())
{
var name = e.Name;
var handler = new Action<object,object>( (o1,o2) =>Console.WriteLine(name));
try
{
e.AddEventHandler(
this,
Delegate.CreateDelegate(
e.EventHandlerType,
handler.Target,
handler.Method
));
}
catch (Exception ex)
{
Console.WriteLine( "Failed to bind to event {0}", e.Name);
}
}
Which seems to work when the event signature is (object,EventArgs) but fails to bind when on certain other events.
Is there a way to do this without necessarily knowing the signature of the event?
You could use the
System.Linq.Expressions.Expressionclass to generate dynamic handlers matching the signature of the event – into which you simply place a call toConsole.WriteLine.The
Expression.Lambdamethod (have provided a link to the specific overload you’d need) can be used to generate aFunc<>or, more likely,Action<>of the correct type.You reflect the delegate type of the event (grabbing it’s
Invokemethod as mentioned by @Davio) to pull out all the arguments and createParameterExpressions for each of those to supply to the lambda method.Here’s a complete solution that you can paste into a standard unit test, I’ll explain afterwards in a follow-up edit:
An outline – we start with a type that has some events (I’m using
Actionbut it should work with anything), and has a method that we can use to test-fire all those events that have subscribers.then to the
DynamicEventBinderclass, which has two methods:GetHandler– to get a handler for a particular event for a particular type; andSubscribeAllEventswhich binds all those events for a given instance of that type – which simply loops over all the events, callingAddEventHandlerfor each, callingGetHandlerto get the handler.The
GetHandlermethod is where the meat and bones is – and does exactly as I suggest in the outline.A delegate type has an
Invokemember compiled into it by the compiler which mirrors the signature of any handler that it can be bound to. So, we reflect that method and get any parameters it has, creating LinqParameterExpressioninstances for each. Naming the parameter is a nicety, it’s the type here that matters.Then we build a single-line lambda, whose body is basically:
(Note here that the event’s name is pulled into the dynamic code and incorporated into a constant string as far as the code is concerned)
When we build the lambda, we also tell the
Expression.Lambdamethod the type of delegate we intend to build (bound directly to the delegate type of the event), and by passing theParameterExpressionarray that we created before, it will generate a method which has that many parameters. We use theCompilemethod to actually compile the dynamic code, which gives us aDelegatewhich we can then use as an argument toAddEventHandler.I sincerely hope this explains what we’ve done – if you’ve not worked with Expressions and dynamic code before it can be mind-bending stuff. Indeed, some of the people I work with simply call this voodoo.