There are plenty of posts on speeding up reflection invokes, examples here:
Speeding up Reflection API with delegate in .NET/C#
https://codeblog.jonskeet.uk/2008/08/09/making-reflection-fly-and-exploring-delegates/
and here:
Example : Speeding up Reflection API with delegate in .NET/C#
My question is about speeding up generic invokes. Is this possible at all?
I've got an abstract class and a class which implements it...
public abstract class EncasulatedMessageHandler<T> where T : Message
{
public abstract void HandleMessage(T message);
}
public class Handler : EncasulatedMessageHandler<MyMessageType>
{
public int blat = 0;
public override void HandleMessage(MyMessageType message) { blat++; }
}
What I want to do is build up a list of these message handler classes and quickly invoke their HandleMessage()
At the moment, I'm doing something that's approximately this:
object handler = Activator.CreateInstance(typeof(Handler)); // Ignore this, this is done up front.
MethodInfo method = type.GetMethod("HandleMessage", BindingFlags.Instance | BindingFlags.Public);
Action<object> hook = new Action<object>(delegate(object message)
{
method.Invoke(handler, new object[] { message });
});
// Then when I want to invoke it:
hook(new MyMessageType());
That's not the whole thing, but it's the important stuff...
The method.Invoke is very slow, I'd like to keep the generic parameters on the class, I realise I could lock this down to object and cast it in the HandleMessage method, but I'm trying to avoid doing this.
Is there anything I can do to speed this up? It's currently orders of magnitude slower than direct calls.
Any help would be appreciated.
Using Delegate.CreateDelegate()
should be a lot faster. You will end up with a pointer to the real function, not a delegate that calls Invoke()
.
Try this:
object handler = Activator.CreateInstance(typeof(Handler));
var handlerType = handler.GetType();
var method = handlerType.GetMethod("HandleMessage", BindingFlags.Instance | BindingFlags.Public);
var paramType = handlerType.GetGenericArguments()[0];
// invoke the MakeHandleMessageDelegate method dynamically with paramType as the type parameter
// NB we're only doing this once
Action<object> hook = (Action<object>) this.GetType().GetMethod("MakeHandleMessageDelegate")
.MakeGenericMethod(paramType)
.Invoke(null, new [] { handler });
In the same class add the following generic method. We invoke this dynamically above because we don't know the type parameter at compile time.
public static Action<object> MakeHandleMessageDelegate<T>(object target)
{
var d = (Action<T>)Delegate.CreateDelegate(typeof(Action<T>), target, "HandleMessage");
// wrap the delegate another that simply casts the object parameter to the required type
return param => d((T)param);
}
You then have a delegate that casts the parameter to the required type, then calls the HandleMessage
method.