Performance of Object.GetType()

We have lots of logging calls in our app. Our logger takes a System.Type parameter so it can show which component created the call. Sometimes, when we can be bothered, we do something like:

class Foo
{
  private static readonly Type myType = typeof(Foo);

  void SomeMethod()
  {
     Logger.Log(myType, "SomeMethod started...");
  }
 }

As this requires getting the Type object only once. However we don't have any actual metrics on this. Anyone got any idea how much this saves over calling this.GetType() each time we log?

(I realise I could do the metrics myself with no big problem, but hey, what's StackOverflow for?)


I strongly suspect that GetType() will take significantly less time than any actual logging. Of course, there's the possibility that your call to Logger.Log won't do any actual IO... I still suspect the difference will be irrelevant though.

EDIT: Benchmark code is at the bottom. Results:

typeof(Test): 2756ms
TestType (field): 1175ms
test.GetType(): 3734ms

That's calling the method 100 million times - the optimisation gains a couple of seconds or so. I suspect the real logging method will have a lot more work to do, and calling that 100 million times will take a lot longer than 4 seconds in total, even if it doesn't write anything out. (I could be wrong, of course - you'd have to try that yourself.)

In other words, as normal, I'd go with the most readable code rather than micro-optimising.

using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;

class Test
{
    const int Iterations = 100000000;

    private static readonly Type TestType = typeof(Test);

    static void Main()
    {
        int total = 0;
        // Make sure it's JIT-compiled
        Log(typeof(Test)); 

        Stopwatch sw = Stopwatch.StartNew();
        for (int i = 0; i < Iterations; i++)
        {
            total += Log(typeof(Test));
        }
        sw.Stop();
        Console.WriteLine("typeof(Test): {0}ms", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (int i = 0; i < Iterations; i++)
        {
            total += Log(TestType);
        }
        sw.Stop();
        Console.WriteLine("TestType (field): {0}ms", sw.ElapsedMilliseconds);

        Test test = new Test();
        sw = Stopwatch.StartNew();
        for (int i = 0; i < Iterations; i++)
        {
            total += Log(test.GetType());
        }
        sw.Stop();
        Console.WriteLine("test.GetType(): {0}ms", sw.ElapsedMilliseconds);
    }

    // I suspect your real Log method won't be inlined,
    // so let's mimic that here
    [MethodImpl(MethodImplOptions.NoInlining)]
    static int Log(Type type)
    {
        return 1;
    }
}

The GetType() function is marked with the special attribute [MethodImpl(MethodImplOptions.InternalCall)]. This means its method body doesn't contain IL but instead is a hook into the internals of the .NET CLR. In this case, it looks at the binary structure of the object's metadata and constructs a System.Type object around it.

EDIT: I guess I was wrong about something ...

I said that: "because GetType() requires a new Object to be build" but it seems this is not correct. Somehow, the CLR caches the Type and always returns the same object so it doesn't need to build a new Type object.

I'm based on the following test:

Object o1 = new Object();
Type t1 = o1.GetType();
Type t2 = o1.GetType();
if (object.ReferenceEquals(t1,t2))
    Console.WriteLine("same reference");

So, I don't expect much gain in your implementation.


I doubt you are going to get a satisfying answer from SO on this subject. The reason being that performance, especially scenarios of this type, are highly application specific.

Someone may post back with a quick stopwatch example of which would be faster in terms of raw miliseconds. But frankly that doesn't mean anything for your application. Why? It depends highly on the usage pattern around that particular scenario. For instance ...

  1. How many types do you have?
  2. How big are you methods?
  3. Do you do this for every method, or only big ones?

These are just a few of the questions that will greatly alter the relevance of a straight time benchmark.