字段与属性的实际性能

时间:2010-12-06 17:52:24

标签: c# reflection reflection.emit

我正在做一些构建后的CIL编织,它将CIL添加到程序集中的所有方法(换句话说,大量的方法)。每个方法检查特定值是否为空。示例(C#Reflector'd版本的CIL代码):

// CIL woven region start
if (MyType.Something == null) {
 // ... some new stuff
}
// CIL woven region end

将MyType.Something作为属性与字段的性能影响是什么?我知道我已经读过C#编译器执行特殊的优化,在这种情况下应该没有性能影响......但是在直接CIL代码(没有C#编译器)的情况下......?或者它是允许这些优化的JIT编译器(因此直接CIL代码仍然有益)?

为静态属性的访问器发出的OpCode.Call会比Ldsfld的性能更差(请记住,由于程序集中的每个方法都是编织的,因此这涉及成千上万的调用)?

感谢。

3 个答案:

答案 0 :(得分:13)

在为SlimDX开发数学库时,我们发现,在.NET 3.5 SP1之前的框架中,使用数学类型成员的字段(例如Vector3的X,Y,Z)会导致不成比例的性能提升在属性。换句话说,对于大量访问属性的小数学函数来说,这种差异是显而易见的。

自.NET 3.5 SP1以来,这已经得到了改进(参见JIT inling)。虽然我认为之前的JIT仍然会内联小方法(属性毕竟只是方法),但早期框架中存在一个错误,它阻止了内联或返回值类型的方法。

请注意,差异在那里仍然很小。除了性能最关键的情况外,我仍然会选择使用属性。

答案 1 :(得分:4)

C#编译器不会对此进行优化,不会 - 但是据我所知,JIT编译器通常可以内联简单(和非虚拟)属性。

与所有表现问题一样:如有疑问,请测试!

答案 2 :(得分:2)

在任何一个方向上效果都很小。如果您的属性看起来像这样::

public static SomeType PropertyName
{
    get {return MyType.propertyName;}
    set {MyType.propertyName = value;}
}

真的应该是一个非常小的差异。 Jit编译器应该将call MyType.set_Property内联到字段加载中,但即使它不能由于错误。我个人在谨慎方面犯错,并坚持使用属性设置器和getter,因为方法体可能会发生变化,因此原始字段访问/突变可能还不够。

如果您想测试,可以强制使用您发出的方法来使用关闭内联或优化的MethodImpl。然后比较差异,我真的怀疑它会很重要。