Why are PropertyInfo SetValue and GetValue so slow?

Miguel Angelo picture Miguel Angelo · Oct 7, 2012 · Viewed 12.4k times · Source

Why is the PropertyInfo methods for getting and setting a property so slow? If I build a delegate using Reflection.Emit, it is much faster.

Are they doing something important, so that the time they take can be justified? That is... am I missing something by using Reflection.Emit to build delegates instead of usign the GetValue and SetValue of the PropertyInfo (aside of development speed)?

PS: Please, give evidence, not only guessing!

Answer

Fabian Schmied picture Fabian Schmied · Oct 12, 2012

The implementation of RuntimePropertyInfo (which is the concrete subclass of PropertyInfo for runtime types) implements GetValue and SetValue by invoking the getter and setter methods via reflection (MethodInfo.Invoke), whereas your generated delegate probably calls the methods directly. Therefore, the question boils down to: why is RuntimeMethodInfo.Invoke so slow when compared to a compiled invocation?

When you decompile (or look at the reference sources for) RuntimeMethodInfo.Invoke, you can see that this is probably because Invoke carries out a lot of tasks:

  • it performs consistency checks (do the number and types of parameters passed match the signature? does the instance passed match the declaring type? was an instance passed although the method is static?),
  • it performs visibility and (if visibility checks are circumvented) security checks,
  • it unwraps the parameters array, treating ref parameters in a special way so that they can be written back to later,
  • it unboxes parameters if necessary,
  • it needs to find the method pointer based on the runtime type handle and method handle associated with the RuntimeMethodHandle and then invoke the method,
  • it boxes the return value if necessary, and
  • it boxes and puts into the parameter array any ref/out parameters.

The runtime will perform similar consistency, security, and visibility checks when it compiles your delegate into executable native code. It also emits code for boxing/unboxing, etc. However, it only needs to do these things once, and can then guarantee that the code is safe to execute. This makes the actual method call a very cheap operation (load the parameters and jump to the method address).

In contrast, every call to RuntimeMethodInfo.Invoke (and thus to GetValue/SetValue) needs to repeat all the work, since the context - parameters, instance, and usage of the return type - is not known. And this is probably why it is so slow.

About what you might be missing: if you emit your own property invocation delegates, you of course need to deal with boxing/unboxing, ref/out parameters, etc. yourself.