18

为什么PropertyInfo获取和设置属性的方法这么慢?如果我使用 构建委托Reflection.Emit,它会快得多。

他们是否在做一些重要的事情,以便他们花费的时间是合理的?那就是......我是否通过使用Reflection.Emit构建委托而不是使用 PropertyInfo 的GetValueSetValue(除了开发速度)而遗漏了一些东西?

PS:请举证,不要只凭猜测!

4

2 回答 2

17

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

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

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

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

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

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

于 2012-10-12T13:33:38.203 回答
15

无需使用 Emit。使用表达式要容易得多。您可以按照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)
   }
于 2013-06-29T11:56:07.523 回答