【问题标题】:Reflection.Emit better than GetValue & SetValue :SReflection.Emit 比 GetValue 和 SetValue 更好:S
【发布时间】:2009-11-26 15:31:53
【问题描述】:

有人告诉我使用 Reflection.Emit 而不是 PropertyInfo.GetValue / SetValue,因为这样更快。 但我真的不知道 Reflection.Emit 中的哪些内容以及如何使用它来替代 GetValue 和 SetValue。有人可以帮我吗?

【问题讨论】:

  • 嗯? Reflection.Emit 允许您动态创建代码以供以后执行。但它也更复杂,更容易出错,更不用说难以调试了。您需要描述您正在尝试使用 GetValue/SetValue 做什么,以及对性能的要求。你为什么首先使用反射?
  • 我猜他有一些动态加载的对象并想要访问该属性,问题是是否调用GetValue/SetValue或生成IL代码来访问“硬编码”属性 会更好。我建议尝试使用 Reflection.Emit.DynamicMethod,然后检查哪个更快。对我来说,GetValue/SetValue 就足够了,我只需要生成 IL 代码来处理在编译时签名未知的事件 :)
  • 我使用反射来获取和设置对象属性的值(我不知道对象的类型)
  • (重新接受答案:请注意,如果您在每次下载时使用 HyperDescriptor,这只会比反射快;它不在 BCL 中)

标签: c# reflection reflection.emit


【解决方案1】:

只是一个替代答案;如果您想要性能,但需要类似的 API - 请考虑 HyperDescriptor;这在下面使用Reflection.Emit(所以你不必这样做),但在PropertyDescriptor API 上暴露自己,所以你可以使用:

PropertyDescriptorCollection props = TypeDescriptor.GetProperties(obj);
props["Name"].SetValue(obj, "Fred");
DateTime dob = (DateTime)props["DateOfBirth"].GetValue(obj);

启用它的一行代码,它处理所有缓存等。

【讨论】:

  • “每次下载使用 HyperDescriptor”是什么意思?我只需要获取属性,获取并设置它们的值,仅此而已
  • 我的意思是您需要从 codeproject 下载 HyperDescriptor 组件并按照页面所示启用它(几种不同的方式)。 没有 HyperDescriptor,这只是美化的反映; HyperDescriptor 拦截 TypeDescriptor 并将反射代码替换为动态 IL。
  • 这很令人困惑,我同意;相同的代码在有/没有 HyperDescriptor 的情况下都可以正常工作,但在没有 HyperDescriptor 的情况下会慢 /much/ (~100x)。让它工作的任何问题,让我知道(这是我几年前写的,但我仍然记得大部分!)
  • 你能告诉我如何在不使用类属性的情况下使用它吗?
  • @Phil 老实说,我现在倾向于使用 FastMember:更简单,也支持“动态”
【解决方案2】:

如果您多次获取/设置相同的属性,那么使用某些东西来构建类型安全的方法确实会比反射更快。但是,我建议使用 Delegate.CreateDelegate 而不是 Reflection.Emit。它更容易正确,而且速度仍然非常快。

我在我的 Protocol Buffers 实现中使用了它,它与 PropertyInfo.GetValue/SetValue 产生了巨大的差异。正如其他人所说,只有在证明最简单的方法太慢之后才这样做。

如果您决定走CreateDelegate 路线,我有一个blog post 提供更多详细信息。

【讨论】:

  • 非常有趣 - 我尝试为 FieldInfo.SetValue 创建一个委托,但它完全没有改变。确实很明显,因为我所做的只是改变了函数的调用方式,而函数本身很慢。那么,您是如何获得这种性能提升的呢?我没有运气在您的博客文章中找到有关它的信息(也许我只是瞎了 :-D)
  • 刚刚重新阅读您的博客文章并发现了 GetGetMethod 和 GetSetMethod 部分,显然我之前失明的。无论如何,这显然解释了速度差异,但是对于 FieldInfos,我仍然一无所知:-S 但是我很期待 Marcs 的例子 :-) 只是想让你知道我发现你做了什么来加快速度代表。
  • 干杯 (+1) - 我只是用这个想法在某些反射填充类上每页节省 0.1 秒 - 0.8 秒 :-)
  • 我尝试实现博客文章中的示例,将MagicMethod 用于SetValue 方法,但它是void,我得到The type 'System.Void' may not be used as a type argument. 异常。我错过了你的教程吗?
  • @Mentoliptus:没有看到你的代码很难说。听起来你应该在一个新问题中展示一个简短但完整的程序。
【解决方案3】:

使用 PropertyInfo.GetValue/SetValue

如果你有性能问题缓存 PropertyInfo 对象(不要重复调用 GetProperty)

如果 - 且仅当 - 使用反射是应用程序的性能瓶颈(如在分析器中所见),请使用 Delegate.CreateDelegate

如果——而且真的只有当——你绝对确定读/写值仍然是最严重的瓶颈,那么是时候开始学习在运行时生成 IL 的有趣世界了。

我真的怀疑这是否值得,这些级别中的每一个都增加了代码的复杂性,而不是提高了性能 - 仅在必要时才这样做。

如果对属性的运行时访问是您的性能瓶颈,那么编译时访问可能会更好(很难同时获得通用和超高性能)。

【讨论】:

    【解决方案4】:

    Reflection.Emit 的目的与 PropertyInfo.Get/SetValue 的目的完全不同。通过 Reflection.Emit,您可以直接发出 IL 代码,例如到动态编译的程序集中,并执行此代码。当然,这段代码可以访问你的属性。

    我严重怀疑这会比最终使用 PropertyInfo 快得多,而且它也不是为此目的而制作的。例如,您可以使用 Reflection.Emit 作为小型编译器的代码生成器。

    【讨论】:

      【解决方案5】:

      使用 Reflection.Emit 似乎有点太“聪明”了,而且是过早的优化。如果您分析您的应用程序,并发现 GetValue/SetValue 反射是瓶颈,那么您可以考虑优化,但可能甚至不会...

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-07-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-04
        相关资源
        最近更新 更多