I'm building a message dispatch map in C# and mostly just playing around with some different approaches. I am curious about a performance difference I am measuring, but it's not obvious why from looking at the IL.
The message map:
delegate void MessageHandler(Message message);
AddHandler(Type t, MessageHandler handler)
{
/* add 'handler' to messageMap invocation list */
}
delegate void GenericMessageHandler<T>(T message);
AddHandler<T>(GenericMessageHandler<T> handler) where T: Message
{
AddHandler(typeof(T), e => { handler((T)e); });
}
Dictionary<Type, MessageHandler> messageMap;
I then have a class hierarchy of Messages, similar to EventArgs in WPF, for example:
public class Message {}
public class VelocityUpdateMessage : Message
and observer classes with handler functions:
void HandleVelocityUpdate(VelocityUpdateMessage message) { ... }
I am measuring 2 ways of adding & invoking handlers. I am wrapping the delegate call so I can get a bit of conceptual type safety and therein lies the perf difference.
Approach 1: listener calls
AddHandler(typeof(VelocityUpdateMessage),
e => { HandleVelocityUpdate((VelocityUpdateMessage)e); });
Approach 2: listener calls
AddHandler<VelocityUpdateMessage>(HandleVelocityUpdate);
Both approaches build a MessageHandler delegate that makes a cast and the same method call, but calling the delegates built using approach #2 is a wee bit slower even though the generated IL looks identical. Is it extra runtime overhead in casting to a generic type? Is it the type constraint? I would expect the JITted delegates to be the same once the generic type is resolved.
Thanks for any info.
The below line creates a new instance of an anonymous type each time it is called. Could that the cause of your performance difference?
AddHandler(typeof(T), e => { handler((T)e); });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With