Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Efficiency of C#'s typeof operator (or whatever its representation is in MSIL)

Tags:

c#

I know premature optimization is the mother of all evil. However, I am defining a generic method that uses Reflection to retrieve its generic type's metadata, and would like to know whether calling typeof(T) several times as in the following code snippet:

private static Dictionary<Type, PropertyInfo[]> elementProperties;

private static T MakeElement<T>(SqlDataReader reader) where T : class, new() {
    PropertyInfo[] properties;
    if (elementProperties.ContainsKey(typeof(T)))
        properties = elementProperties[typeof(T)];
    else
        properties = elementProperties[typeof(T)] = typeof(T).GetProperties();

    // more code...
}

... is less efficient than storing the type object into a variable as in the following code snippet:

private static Dictionary<Type, PropertyInfo[]> elementProperties;

private static T MakeElement<T>(SqlDataReader reader) where T : class, new() {
    PropertyInfo[] properties;
    Type type = typeof(T);
    if (elementProperties.ContainsKey(type))
        properties = elementProperties[type];
    else
        properties = elementProperties[type] = type.GetProperties();

    // more code...
}

...?

If I understand compiler theory correctly (and I think I do), this question could be reduced to the following one:

When the JIT compiler instantiates a generic type, does it replace every instance of [whatever the MSIL representation of typeof(T) is] with...

  1. ... a reference to the actual type object? (good)
  2. ... a method call/subroutine/whatever that retrieves a reference to the actual type object? (bad)
  3. ... a method call/subroutine/whatever that constructs a type object and returns a reference to it? (very, very bad)
like image 801
pyon Avatar asked Jun 20 '11 21:06

pyon


People also ask

What is efficiency in C language?

The most fundamental data type in the C language is the integer, whichis normally defined as the most efficient type for a given processor. The C language treats this type specially in that the language does notoperate on smaller types, at least conceptually speaking.

Why is C the most efficient language?

In that case, “C is the best solution, since it is dominant in both single objectives,” the researchers write. If you're trying to save time while using less memory, C, Pascal, and Go “are equivalent” — and the same is true if you're watching all three variables (time, energy use, and memory use).

Which is faster C or C+?

Performance: C++ is widely used when higher level languages are not efficient. C++ code is much faster than C# code, which makes it a better solution for applications where performance is important.

Which programming language is more efficient C or assembly?

Actually, the short answer is: Assembler is always faster or equal to the speed of C. The reason is that you can have assembly without C, but you can't have C without assembly (in the binary form, which we in the old days called "machine code").


1 Answers

A little intuition should tell you that declaring a single instance of a variable to hold the result of GetType(), which is then used throughout the rest method would be more efficient (and more readable to boot)

Here is the IL of the two methods:

MakeElement 1:

Icall       System.Type.GetTypeFromHandle
callvirt    System.Collections.Generic.Dictionary<System.Type,System.Reflection.PropertyInfo[]>.ContainsKey
brfalse.s   IL_002F
ldarg.0     
ldfld       elementProperties
ldtoken     01 00 00 1B 
call        System.Type.GetTypeFromHandle
callvirt    System.Collections.Generic.Dictionary<System.Type,System.Reflection.PropertyInfo[]>.get_Item
pop         
br.s        IL_0053
ldarg.0     
ldfld       elementProperties
ldtoken     01 00 00 1B 
call        System.Type.GetTypeFromHandle
ldtoken     01 00 00 1B 
call        System.Type.GetTypeFromHandle
call        System.Type.GetProperties
callvirt    System.Collections.Generic.Dictionary<System.Type,System.Reflection.PropertyInfo[]>.set_Item

MakeElement 2:

call        System.Type.GetTypeFromHandle
stloc.0     
ldarg.0     
ldfld       elementProperties
ldloc.0     
callvirt    System.Collections.Generic.Dictionary<System.Type,System.Reflection.PropertyInfo[]>.ContainsKey
brfalse.s   IL_0028
ldarg.0     
ldfld       elementProperties
ldloc.0     
callvirt    System.Collections.Generic.Dictionary<System.Type,System.Reflection.PropertyInfo[]>.get_Item
pop         
br.s        IL_003A
ldarg.0     
ldfld       elementProperties
ldloc.0     
ldloc.0     
callvirt    System.Type.GetProperties
callvirt    System.Collections.Generic.Dictionary<System.Type,System.Reflection.PropertyInfo[]>.set_Item

You save 1 or 2 calls to System.Type.GetTypeFromHandle by declaring it in the local variable. I'm not certain that the JIT'ing process won't compile those out, but I would personally put more faith in the compiler to optimize the IL for things like over the JIT'er, but that's just me.

like image 185
Brandon Moretz Avatar answered Oct 05 '22 18:10

Brandon Moretz