2009-07-22 53 views

回答

2

反射性能很好,它只是确实比静态代码多

说你有这样的代码片段:

typeof(SomeClass).GetMethod("SomeStaticMethod"). 
Invoke(null, new object[] { 1, 2, 3 }); 

这是与此相同:

SomeClass.SomeStaticMethod(1, 2, 3); 

但它应该是显而易见的是,第一个有很多工作要做。它必须获取类型信息,遍历它以查看是否存在SomeStaticMethod方法,检查它是什么类型的方法,在实例上调用该方法,或者如果它是静态的,则不传递对象数组参数,装箱/拆箱整数在这种情况下也是如此。

这可能是一个非常广泛的总结,毫无疑问更多的事情正在进行。尽管如此,反射速度仍然很快,并在很多领域使用,从WinForms的数据绑定到ASP中的模型绑定。NET MVC(你对这个站点建立的每一个请求,建立在MVC上,涉及到大量的反射,然而,这个站点非常快,MVC被认为是一个非常快速的框架)。

1

因为它涉及在运行时查找的字符串(类型和成员名称的),以及额外的装箱/拆箱值类型。

4

上了不起的文章MSDN:Dodge Common Performance Pitfalls to Craft Speedy Applications。基本上,这是一个迟到和早期约束的问题。也就是说,可以在编译时决定什么,以及在运行时必须决定什么。那篇文章...

后期绑定案件 MethodBase.Invoke,DynamicMethod的通过 调用,Type.InvokeMember和 后期绑定代理呼叫(通过Delegate.DynamicInvoke上 代表呼叫)。 所有这些方法都具有比 早期绑定的情况下 显著负 性能的影响。即使在最好的情况下,它们的典型范围是 的幅度比最慢的 早期的情况。

他打破了我们进行早期和晚期调用的各种方式的不少性能测试。值得一读。

1

反射涉及将元数据来解析名称的标记,它然后使用该令牌进行查找和检索所需的数据(例如,一个方法令牌用于获取有关方法的信息,参数.. 。等等)。

由于2个原因,此过程很昂贵。 1-很多查找正在进行中。 2-触摸通常不会触及的页面(冷页面),其中包含元数据表格。

直接访问元数据非常昂贵,CLR维护缓存以使此过程更快,并避免在以非反射方式访问事物时触及元数据表,但是一旦进入反射状态,我们会绕过这些缓存并直接进入来源。

16

反射效果并不是很好

这是一个非常加载声明。 “表现良好”是相对的。与静态代码相比,反射式呼叫不会执行,也不会执行。但是,在几乎所有情况下,.NET中的反射都是非常快的。我无法低估这一点。反思在.NET 1.x和其他语言中得到了不好的声誉,但是在.NET 2.0+中的反射是,并且很快就出现了

的情况下,99%的“是反映太慢”是一个无关紧要的问题。我怀疑你需要费心衡量一个反射电话对静态电话的性能影响。

+0

嗯,我在Windows窗体应用程序中使用反射来创建一个动态的用户界面,我没有看到任何性能问题。当然,在我不知道的“高性能关键”应用程序中可能会有所不同。 – Malcolm 2009-07-22 01:43:50

0

反射在.NET中表现良好 - 它具有的功能。

然而,反思,因为它已经编译类型的运行时分析,需要相当多的开销。一般来说,像静态类型信息的字符串查询,以及漫游类元数据等,都需要一段时间。

这并不是说它真的很慢 - 它只是比完全编译的海峡方法调用和查找慢得多。它应该是 - 但我真的更多地想到它,因为在任何系统中,编译代码比动态查找信息更快。

5

简单地说,“反射”执行缓慢是在很宽的毯子底下包含许多功能的地狱。 .NET中的反射有几个类,每个类都有不同的“性能”级别。首先,使用typeof()运算符实际上是一种反射形式...它查询CLR元数据的类型。然而,typeof()执行得非常快(在接近空闲时间)。使用其他类型相关的“反射”,如is运算符,sizeof()运算符等也几乎是免费的(它们基本上就像静态代码一样执行。 )

考虑到指针遍历和元数据探测的数量,用于检索类型信息的反射速度比typeof()慢,也是非常非常快的。元数据探测是.NET代码的一种常见做法,尤其是在处理自定义属性时。

关于反射的重要性能问题与调用有关。访问类型信息和读取元数据的权重相当轻。当涉及动态调用属性,索引器,方法或通过反射动态构造新类型时,您会获得数量级的性能优势。

反射仍然是一个进程内执行,所以在你担心动态调用的性能下降之前,请确保没有任何明显更大的性能瓶颈,如进程间执行,网络调用(即数据库,Web服务等)当涉及到性能时,从最大的性能开始,然后从这里开始。包括动态调用在内的反射通常是从性能角度考虑的最后一件事情。

附录:

的思想后一点,但如果你需要高度的后期绑定类型成员的动态调用的,你应该看看轻量级代码生成。使用System.Reflection.Emit命名空间,您可以使用DynamicMethod等实用程序在运行时生成轻量级代码,以执行早期绑定的调用。对生成的代码进行缓存可以降低生成代码的初始成本,使您可以利用早期绑定的性能获得后期绑定的呼叫。