Search code examples
c#performancetypes

Performance cost of type comparisons


I am decoding comms messages from a binary stream. I create message objects of varying types depending on what messages have arrived. They all derive from a base CommsMessage type. All fine and dandy.

Elsewhere in my code I need to react to these messages, so I need to know what type of message it is.

Currently I am doing:

void ProcessIncomingMessage(CommsMessage msg)
{
    if (msg is MessageType1)
        return ProcessMessageType1(msg as MessageType1);

    if (msg is MessageType2)
        return ProcessMessageType2(msg as MessageType2);

    //etc
}

I am wondering what the performance cost of comparing these types are, and whether I should include a MessageType property in the base class instead. Then I could do:

void ProcessIncomingMessage(CommsMessage msg)
{
    switch (msg.MessageType)
    {
         case MessageType.Type1:  return ProcessMessageType1(msg as MessageType1);
         case MessageType.Type2:  return ProcessMessageType2(msg as MessageType2);

         //etc
    }
}

Yes, this is premature optimisation, and I'm probably worrying over insignificant details, but I'm the kind of coder who likes to know what's going on under the covers and so was wondering the performance differences between the two. I guess I have a prejudice against type comparisons from my C++ background where RTTI introduced an overhead, and just wondered if .Net had any similarities.


Solution

  • Have you considered eliminating the type casts?

    I'm guessing you've considered that putting the virtual method on the Message type itself would break a layering abstraction (e.g. you might want a clean separation of the processing of the message from the message itself). Maybe consider the visitor pattern. This will allow you to separate out the Message class from the processing of the Message itself.

    If you have something of this structure.

    abstract class CommsMessage {}
    class Message1 : CommsMessage {}
    class Message2 : CommsMessage {}
    

    You could refactor to

    abstract class CommsMessage 
    { 
        public abstract void Visit(CommsMessageVisitor v);
    }
    
    class Message1 : CommsMessage 
    {
        public void Visit(CommsMessageVisitor v) { v.Accept(this); }
    }
    
    class Message2 : CommsMessage 
    {
        public void Visit(CommsMessageVisitor v) { v.Accept(this); }
    }
    
    interface CommsMessageVisitor 
    {
       void Accept(Message1 msg1);
       void Accept(Message2 msg2);
    }
    

    At this point, you've eliminated the type-casts. You can now rewrite your code as

    void ProcessIncomingMessage(CommsMessage msg) 
    {
      new MyVisitor().Visit(msg);
    }
    
    class MyVisitor : CommsMessageVisitor
    {
        void Accept(Message1 msg1) { ProcessMessageType1(msg1); }
        void Accept(Message2 msg2) { ProcessMessageType2(msg2); }
    }
    

    Of course there might be reasons you can't do this, but it's always nicer to avoid type casts if you can!