20

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!

svick
  • 236,525
  • 50
  • 385
  • 514
Miguel Angelo
  • 23,796
  • 16
  • 59
  • 82
  • 4
    Fyi, if you're looking for an easier way of getting a performance boost than Reflection.Emit, you could just Delegate.CreateDelegate with PropertyInfo.GetGetMethod / PropertyInfo.GetSetMethod (and cache the delegate of course). – Ani Oct 07 '12 at 08:01
  • I'd have to lock the instance of the object in the delegate. The methods `GetValue` and `SetValue` take the object instance, at the time of the call. – Miguel Angelo Oct 07 '12 at 08:04
  • Delegate.CreateDelegate can create both open and closed-instance delegate objects. – Ani Oct 07 '12 at 08:06
  • It is not for easyness, I am looking for something like: "you should use `PropertyInfo.GetValue` method because of security issues." or something like that. I want to know if I am missing something. – Miguel Angelo Oct 07 '12 at 08:07
  • Yeah... they say `Delegate.CreateDelegate` for `static` methods also support instance methods. Very confusing! If you didn't say I'd never know that. Thanks! – Miguel Angelo Oct 07 '12 at 08:13
  • Is that really faster to (emit + create type + create delegate + call delegate) rather than (get type + get property info + get/set value)? – zahir Oct 09 '12 at 20:45
  • I only see an advantage when caching the delegate. It is faster to (get delegate from cache + call delegate) than (get property info from cache + get/set value). If results are not cached, then I guess reflection is faster. – Miguel Angelo Oct 10 '12 at 00:27

2 Answers2

18

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.

Fabian Schmied
  • 3,885
  • 3
  • 30
  • 49
17

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)
   }
Community
  • 1
  • 1
Fried
  • 1,323
  • 12
  • 21
  • http://stackoverflow.com/questions/1027980/improving-performance-reflection-what-alternatives-should-i-consider – sky-dev Apr 14 '15 at 15:38
  • @Fried Your link is broken whereas sky-devs link works. I guess thats his point. – ViRuSTriNiTy Aug 09 '16 at 16:10
  • I put the article on SO => see http://stackoverflow.com/questions/17660097/is-it-possible-to-speed-this-method-up/17669142#17669142 – Fried Aug 10 '16 at 13:22
  • Does not work if the property is private set or init – jjxtra Mar 09 '23 at 21:02
  • @jjxtra Private properties seems to work with correct binding flags. If not, cann you give an example?: var propertyInfo = typeof(Person).GetProperty("PrivateName", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); var propertyGetter = FastInvoke.BuildUntypedGetter(propertyInfo!); – Fried Mar 10 '23 at 09:33