Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does caching the return value of typeof(MyControl) provide any optimization?

I see code similar to the following sprinkled about some native WPF controls:

static MyControl {
    Type typeFromHandle = typeof(MyControl);

    // Which is used in various places
    SomeProperty.OverrideMetadata(typeFromHandle, ...);
    CommandManager.RegisterClassInputBinding(typeFromHandle, ...);
    EventManager.RegisterClassHandler(typeFromHandle, ...);
}

Seems like the following code would have the same performance:

static MyControl {
    SomeProperty.OverrideMetadata(typeof(MyControl), ...);
    CommandManager.RegisterClassInputBinding(typeof(MyControl), ...);
    EventManager.RegisterClassHandler(typeof(MyControl), ...);
}

Does this approach offer any benefit performance wise when JIT-ing the code or during runtime?

like image 382
CodeNaked Avatar asked Jun 02 '11 13:06

CodeNaked


3 Answers

Short answer

Yes, it is more optimal, but no, you shouldn't use it, as in almost every case it is a premature optimization. If anything, use it as a way to maintain readability in code if you use typeof(MyControl) many times.

Long answer

If you look at the IL produced from a typeof(MyControl) statement in C#, you see the following:

IL_0001: ldtoken [mscorlib]MyControl
IL_0006: call class [mscorlib]System.Type
        [mscorlib]System.Type::GetTypeFromHandle(
            valuetype [mscorlib]System.RuntimeTypeHandle)

These instructions do the following:

  1. Loads the RuntimeTypeHandle (the ldtoken IL instruction) onto the stack (the CLR one, not C#/.NET concept of one).
  2. Get the Type from the RuntimeTypeHandle (the call to Type.GetTypeFromHandle).

Compare this to assigning a Type variable type with one stored in an instance:

IL_0014: ldloc.2

Note, the location (1, 2, etc.) will vary depending on other variables, but ultimately, it is a load of a reference type.

Comparing the two, the call to an already-assigned variable is always going to be faster. The first has to load the type handle and then it has to call a method in order to resolve the handle into a Type; the second method is just a reference to a local variable.

However, like most other posts, this could most definitely be considered a case of premature optimization, so I would suggest not looking to do this if you think that your code is underperforming.

The argument can be made that it is better from a code reuse standpoint, as if you had to change the type, you would change it in less places; you won't be awash in a sea of typeof statements.

Finally, in regards to WPF, this is something that they had to do, given the requirements for performance (as any UI system has); WPF has a tremendous amount of managed objects, many more compared to Windows Forms and has to take into account the performance of those objects so that it can render the UI as quick as possible.

As a result, you would see something like this:

private static readonly object TrueObject = true;
private static readonly object FalseObject = false;

// Later on.
DoSomething(condition ? TrueObject : FalseObject);

// Where
void DoSomething(object value)
{
    // Compare to true/false objects.
    if (value == TrueObject)
    {
        // True case.
    }
    else if (value == FalseObject)
    {
        // False case.
    }
    else
    {
        // Invalid.
        throw new InvalidOperationException();
    }
}

The reason for this is simple; most of WPF exposes properties/methods with objects as parameters instead of strongly-typed values. When value types are involved, it can involve a tremendous amount of boxing/unboxing.

In order to get around this, they have a single instance which is boxed/unboxed when they know exactly which values are going to be boxed/unboxed; with a bool, it's easy, there is only true and false.

Again, I wouldn't necessarily recommend this approach for almost any system, but for some systems, it makes sense.

In your case, I'd simply assign the type to a variable, only for readability purposes, not for performance. If you have performance issues, look at the overall process first, isolate through measurements, and then proceed from there.

like image 33
casperOne Avatar answered Nov 14 '22 00:11

casperOne


Caching of typeof will give you a small performance boost. The following page gives the benchmarks:

Typeof expression used: 2.55 ns
Type object cached:     0.64 ns

If you typeof a lot, or care about nanoseconds, then this might matter to you!

like image 195
ColinE Avatar answered Nov 14 '22 00:11

ColinE


It's unlikely you'll write code where the performance of typeof is significant so you should choose the style of code that is most clear and maintainable.

like image 5
David Heffernan Avatar answered Nov 14 '22 01:11

David Heffernan