反思真的很慢吗?

时间:2012-01-13 06:52:15

标签: c# performance reflection

这是一种普遍的看法,即反思很慢,并试图尽可能地避免它。但在目前的情况下,这种信念是否属实?目前的.net版本有很多变化,比如使用IL Weaving(即IL Emit)等,而不是传统的PropertyInfo和MethodInfo进行反射的方式。

是否有任何令人信服的证据,新的反映不再那么慢,而且可以使用。有没有更好的方法来读取属性数据?

谢谢, 巴斯卡尔

7 个答案:

答案 0 :(得分:12)

当你想到这一点时,反思对它的速度有多么令人印象深刻。

来自ConstructorInfoMethodInfo的缓存委托的调用速度可与其他任何委托相媲美。

ILGenerator.Emit创建的委托(顺便提一下不是新的,从版本1开始就在.NET中)也可以同样快速地调用。

通过发出或调用ConstructorInfo的委托获得的对象将与任何其他对象一样快。

如果通过动态加载程序集来获取对象,使用反射来查找要调用的方法并调用它,并且它实现了一个已定义的接口,通过该接口可以从该点开始调用它,那么它就像快速了解它如何用作该界面的另一种实现。

总而言之,反射为我们提供了做事的方法,没有它我们会 - 如果我们可以完成它们 - 必须使用速度慢的代码和执行技术。

它还为我们提供了比其他方式更复杂,更脆弱,更少类型安全且性能更低的方法。几乎每一行C#代码都可以被一大堆使用反射的代码所取代。在很多方面,这段代码几乎肯定会比原始代码差,而性能是其中最少的。

很可能“避免反思,因为它的缓慢”建议源于这样一种信念,即那种只会因为看起来很酷而对任何新技术感到疯狂的开发者会被“它更可能被警告” “会慢”,“它会不那么惯用,更容易出错,更难维护”。很可能这种信念是完全正确的。

在大多数情况下,当最自然和最明显的方法是使用反射时,它的性能也不会低于避免它的真正错综复杂的尝试。

如果性能问题适用于反射中的任何内容,那么它实际上是隐藏的用途:

在只有少量工作可以避免它的情况下,使用dynamic似乎是明智的。这里的性能差异可能值得考虑。

在ASP.NET中,使用<%#DataBinder.Eval(Container.DataItem, "SomeProperty")%><#((SomeType)Container.DataItem).SomeProperty%><%#SomeCodeBehindProvidedCallWithTheSameResult%>更容易,但通常效率更低。我仍然会使用前者的90%,而后者只有在我真正关心给定页面的性能时才会使用,或者更可能因为对同一个对象进行多次操作会使后者更自然。

总而言之,计算机中的一切仍然“缓慢”,而它们受限于需要以消耗能量并花费时间的方式在单个宇宙中工作,对于某些“慢”的值。不同的反射技术有不同的成本,但替代方案也是如此。要注意的是,在隐藏反射这种显而易见的方法的情况下,不要过多地反思,而另一种稍微不那么明显的方法可能效果很好。

当然,使用您使用的任何技术都可以明智地编码。如果你要连续一百次调用同一个委托,那么你应该存储它而不是每次调用都能获得它,而且无论是通过反射获取它的方式都是如此。

答案 1 :(得分:7)

一切都取决于 是的,使用反射毫无疑问比不使用反射慢,但你必须看一下大局:

例如,假设您的代码进行了一些反射,然后通过网络从数据库加载一些数据 在这种情况下,您可以完全忽略反射的额外成本,因为通过网络的数据库请求可能需要更长时间。

答案 2 :(得分:1)

我不会担心性能成本太高。并不是说性能无关紧要,但在很多情况下,毫秒或两秒不明显或者值得选择更复杂的编码方案。看看here

我通常更喜欢这种方法:

  1. 编写简单代码
  2. 衡量绩效
  3. 如果需要,优化最大的击球手

答案 3 :(得分:1)

你的意思是提到一个共同的信念?反思不是一个坚实的障碍。你应该考虑每种方法。例如,通过默认构造函数创建对象比简单调用慢几倍,而创建参数化构造函数则慢十几倍。因此,如果您想研究速度,请做一个基准测试并对您需要的具体功能进行基准测试。

PS。使用C#,你可以随时创建和compile expressions,如果你设法做到这一点会比反射快得多。

答案 4 :(得分:0)

是的,当我们尝试对庞大的操作或循环进行时,反射很慢。 你也可以尝试动态选项。使用动态选项,它可以被缓存,最终将比反射更快。

答案 5 :(得分:0)

如果您需要查看应用于源代码的属性,那么您几乎必须使用反射。

某些反射操作很快,例如Object.GetType(),但有些操作相对较慢,例如Type.FindMethod(“MyMethod”)。

一般情况下,我会说如果您的应用程序偶尔使用Reflection,那么应该没有性能问题。另一方面,如果你的应用程序广泛使用Reflection,那么你可能会看到一些缓慢。

答案 6 :(得分:0)

内省是一项繁重的工作。说慢是相对于很多事情。通过反射调用方法/构造函数很慢,但使用反射只能检索metadatas不是。

请记住,反射必须仅用于检索元数据。 如果需要调用方法,运行某些东西,只需在初始化时发出动态类型/方法,并通过接口/委托调用它们。