为什么PropertyInfo SetValue和GetValue这么慢?

时间:2012-10-07 07:56:27

标签: .net reflection reflection.emit propertyinfo

为什么获取和设置属性的PropertyInfo方法如此之慢?如果我使用Reflection.Emit构建委托,则速度要快得多。

他们是否正在做一些重要的事情,以便他们采取的时间是合理的?那是......我错过了一些东西,使用Reflection.Emit来构建代理而不是使用PropertyInfo的GetValueSetValue(除了开发速度)?

PS:请提供证据,不仅要猜测!

2 个答案:

答案 0 :(得分:16)

RuntimePropertyInfo(它是运行时类型的PropertyInfo的具体子类)的实现通过反射调用getter和setter方法来实现GetValueSetValue({ {1}}),而您生成的委托可能直接调用方法。因此,问题归结为:与编译调用相比,为什么MethodInfo.Invoke这么慢?

当你反编译(或查看参考资料来源)RuntimeMethodInfo.Invoke时,你可以看到这可能是因为RuntimeMethodInfo.Invoke执行了很多任务:

  • 它执行一致性检查(传递的参数的数量和类型是否与签名匹配?传递的实例是否与声明类型匹配?虽然方法是静态的,但是传递了一个实例?),
  • 它执行可见性和(如果绕过可见性检查)安全检查,
  • 它展开参数数组,以特殊方式处理ref参数,以便以后可以将它们写回来,
  • 如果需要,它会取消装箱参数,
  • 它需要根据与RuntimeMethodHandle关联的运行时类型句柄和方法句柄找到方法指针,然后调用方法,
  • 如果需要,它会包含返回值,
  • 它将参数数据框放入参数数组中。

运行时将代理编译为可执行本机代码时,将执行类似的一致性,安全性和可见性检查。它还会发送装箱/拆箱等的代码。但是,它只需要执行一次这些操作,然后可以保证代码可以安全执行。这使得实际方法调用非常便宜(加载参数并跳转到方法地址)。

相反,每次调用Invoke(以及RuntimeMethodInfo.Invoke / GetValue)都需要重复所有工作,因为上下文 - 参数,实例和返回的用法类型 - 不知道。这可能就是为什么它如此缓慢。

关于您可能缺少的内容:如果您发出自己的属性调用委托,您当然需要自己处理装箱/取消装箱,参考/退出参数等。

答案 1 :(得分:13)

无需使用Emit。使用Expression要容易得多。 您可以按照中所述加快访问速度 SO。 辅助类为getter或setter创建一个“方法指针”(Action / Func)。如果重复使用Action / Func,您将能够像普通的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)
   }