header image
 

Class markers: attributes, interfaces or something else?

You probably had to make such decision in the past. We have a number of classes, probably inheriting from some base. We need to mark some of them in a way that we can process their objects differently than the rest. To make a concrete example: entity components in Heimdall. Components are basic data containers for entities. Markers come into the picture when serializing entities: some components should be sent from server to the client (name, location, etc), while others contain internal object state only needed by the server. We need a way to mark “client-side” ones so that the entity serializer can properly filter data. What options are there?

  1. Attributes
        [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
        sealed class MyAttribute1 : Attribute
        {
            public MyAttribute1()
            {
            }
        }
    
        [MyAttribute1]
        class Class1
        {
        }
    
        var obj = new Class1();
        if (obj.GetType().IsDefined(typeof(MyAttribute1), false))
            ...
    

    The cleanest way, preferred by the .NET Framework Design Guidelines. Unfortunately testing if an object’s class has a particular attribute applied is clunky and involves reflection.

  2. Marker interfaces
        interface Interface1
        {
        }
    
        class Class1 : Interface1
        {
        }
    
        var obj = new Class1();
        if (obj is Interface1)
            ...
    

    Even cleaner than attributes in my opinion, easy testing, no reflection involved – what’s not to like? Well, the above guideline expressly tells us to avoid empty interfaces. It makes sense, interfaces are behavioral contracts, so an empty one isn’t very logical if you think about it. Still many people use them just for their syntactic simplicity.

  3. Virtual properties
        class Class0
        {
            public virtual int type { get { return 0; } }
        }
    
        class Class1 : Class0
        {
            public override int type { get { return 1; } }
        }
    
        Class0 obj = new Class1();
        if (obj.type == 1)
            ...
    

    Pretty simpe as well, easy testing and little overhead. Not very popular technique for the job though.

  4. Public fields
        class Class0
        {
            public int type = 0;
        }
    
        class Class1 : Class0
        {
            public Class1()
            {
                type = 1;
            }
        }
    
        Class0 obj = new Class1();
        if (obj.type == 1)
            ...
    

    We can expect this to be the fastest solution: no virtual calls, no overhead at all. Of course no sane designer would recommend public fields… 😉

So what did I choose as my solution? Component serialization happens quite often so speed is the primary requirement. Memory usage is also a big concern – when the game world is populated there will be thousands components present in the entity system engine. Well, I’m sure you know what happens next… Yeah, that’s right – let’s benchmark stuff!

Class markers microbenchmark code Show

And the results:

Instantiating 1000000 objects... 00:00:00
Interfaces:     00:00:00.0299656, 333887 333275 332838
Classes:        00:00:00.0183586, 333887 333275 332838
Fields:         00:00:00.0134517, 333887 333275 332838
Properties:     00:00:00.0187774, 333887 333275 332838
Attributes:     00:00:03.3878258, 333887 333275 332838

Not that surprising really.

  • Fields are fastest. Using them would increase memory footprint though, as each and every component instance would contain a marker field.
  • Properties are as fast as testing for object’s class directly and incur no memory overhead.
  • Testing interfaces is slower than classes/properties. Still not that much slower.
  • As expected, testing for attributes is dead slow. Over 100x slower than interfaces in fact. That makes them absolutely useless in any kind of performance-sensitive code despite design guidelines. Sorry. Of course you can cache the result somehow or generate some clever IL code to test in runtime… but that’s a bit overkill for such simple task.

So the winner is… Properties! At least in my case. Just remember, if speed is not your primary concern, attributes are perfectly fine.

~ by omeg on July 10, 2012.

C#, code, Heimdall, performance

3 Responses to “Class markers: attributes, interfaces or something else?”

  1. Each of my component types has an ID number (POSITION_COMPONENT=0,WEAPONS_COMPONENT=1, etc.) but they are not properties, they are indices to an array of containers which hold each component type. I just arranged them so that shared, server-only and client only components are in their own ranges, then I can filter easily during serialization.

  2. Thanks! I really wanted to refactor some legacy code to test for marker interfaces instead of using a long condition testing class types. However, reading your benchmark made me think I might not want to incur this performance impact.

    Also, it’s worth noting that your benchmarking code uses uniform distribution when decided the class of each instantiated object. This may not always be the case and one can arrange the classes in the condition in a way that the most common classes will satisfy the condition sooner, thus achieving better performance overall. Less common classes will require a bit more time to test for.

Leave a Reply