Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is casting to a generic type slower than an explicit cast in C#?

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.

like image 283
Chronic Game Programmer Avatar asked Jan 21 '12 08:01

Chronic Game Programmer


1 Answers

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); }); 
like image 72
Jonathan Allen Avatar answered Sep 28 '22 01:09

Jonathan Allen