Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are PropertyInfo SetValue and GetValue so slow?

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!

like image 407
Miguel Angelo Avatar asked Oct 07 '12 07:10

Miguel Angelo


2 Answers

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.

like image 133
Fabian Schmied Avatar answered Nov 02 '22 15:11

Fabian Schmied


There is no need to use Emit. It is far more easy to use Expression. You can speed up the access as described in SO. The helper class creates a "method pointer" (Action/Func) to the getter or setter. If you reuse the Action/Func you will be able to perform as fast as a normal setter.

   // creating setter (once)
   var propertyInfo = typeof(T).GetProperty(field);
   var setter = FastInvoke.BuildUntypedSetter<T>(propertyInfo));

   // usage somehow later in a loop of data
   foreach(var myobject in MySource)
   {
     setter(myobject, myValue)
   }
like image 36
Fried Avatar answered Nov 02 '22 14:11

Fried