.NET中属性的性能开销

我在某个地方读到,拥有公共财产比在一个class级中拥有公共成员更可取。

  1. 这只是因为抽象和模块化吗? 还有其他任何超越原因吗?

  2. 属性访问由编译器转换为函数调用。 对于没有备份存储的属性(例如, public string UserName { get; set; } ),与直接成员访问相比,性能开销会是多少? (我知道它通常不会有所作为,但在我的一些代码中,属性被访问了数百万次。)

Edit1:我在整数成员和属性上运行了一些测试代码,公共成员的速度是属性的3-4倍。 (在调试中~57 ms.vs~206 ms。在Release中57与97 vs. 97是最常见的运行值)。 对于1000万次读写,两者都足够小,不足以certificate改变任何东西。

码:

  class TestTime1 { public TestTime1() { } public int id=0; } class TestTime2 { public TestTime2() { } [DefaultValue(0)] public int ID { get; set; } } class Program { static void Main(string[] args) { try { TestTime1 time1 = new TestTime1(); TestTime2 time2 = new TestTime2(); Stopwatch watch1 = new Stopwatch(); Stopwatch watch2 = new Stopwatch(); watch2.Start(); for (int i = 0; i < 10000000; i++) { time2.ID = i; i = time2.ID; } watch2.Stop(); watch1.Start(); for (int i = 0; i < 10000000; i++) { time1.id = i; i = time1.id; } watch1.Stop(); Console.WriteLine("Time for 1 and 2 : {0},{1}",watch1.ElapsedMilliseconds,watch2.ElapsedMilliseconds); } catch (Exception ex) { Console.WriteLine(ex.Message); } Console.In.ReadLine(); } } 

这只是因为抽象和模块化吗? 还有其他任何超越原因吗?

从来没听说过; 这些原因本身就足以引人注目。 但也许其他人会加入这个。

属性访问由编译器转换为函数调用。 对于没有备份存储的属性(例如,公共字符串UserName {get; set;}),与直接成员访问相比,性能开销会是多少? (我知道它通常不会有所作为,但在我的一些代码中,属性被访问了数百万次。)

在生成的中间语言中,属性访问被转换为方法调用。 但是,正如单词所说,这只是一种中间语言:它将及时编译为其他内容。 此转换步骤还涉及优化,例如内联简单的属性访问器等简单方法。

我希望(但你需要测试以确保)JITter负责这样的访问器,因此应该没有性能差异。

连续运行测试20次,确保在发布版本中启用了JIT优化:

 Time for 1 and 2 : 47,66 Time for 1 and 2 : 37,42 Time for 1 and 2 : 25,36 Time for 1 and 2 : 25,25 Time for 1 and 2 : 27,25 Time for 1 and 2 : 25,25 Time for 1 and 2 : 26,25 Time for 1 and 2 : 25,25 Time for 1 and 2 : 25,25 Time for 1 and 2 : 25,25 Time for 1 and 2 : 25,25 Time for 1 and 2 : 25,25 Time for 1 and 2 : 25,25 Time for 1 and 2 : 25,25 Time for 1 and 2 : 25,25 Time for 1 and 2 : 25,25 Time for 1 and 2 : 25,25 Time for 1 and 2 : 25,25 Time for 1 and 2 : 25,25 Time for 1 and 2 : 25,25 

是的,JITter擅长内联属性访问器。 Perf不是问题,不应该考虑。

不要担心性能开销。 它太小了,你不应该考虑削弱类的封装; 这将是最糟糕的过早优化。

它主要用于抽象(您可以在以后添加validation而不破坏现有代码或需要重新编译)。

即使使用自动属性,编译器仍然会生成一个支持字段,并将执行此操作。

确保使用Ctrl-F5而不是F5运行; 否则调试器仍将附加,并且某些优化可能无法正常工作,即使在发布模式下也是如此。 至少在我的机器上就是这种情况:F5给出与你发布的结果类似的结果,而Ctrl-F5给出相同的结果。

1)它用于封装原则,但其他.NETfunction使用数据绑定等属性。

2) 我不确定我同意这一点,我总是听说如果属性是直接获取/设置它与标准字段访问一样快 – 编译器会为你做这件事。

更新:似乎是两者兼而有之,编译方法调用但JIT优化了。 无论哪种方式,这种性能问题都不会对您的代码产生有意义的影响。 但是,请注意,围绕实施属性的指导是使它们尽可能轻,呼叫者不希望它们昂贵。

在我发布这篇文章之后,我意识到它基本上是为了隐藏你对象的内部工作原理。

我以前问了同样的问题 。

我猜你正在使用VS2008,正在使用64位操作系统并将编译设置为“任何CPU”? 如果是这样,x64 JIT编译器不会内联属性。 它们使用32位,使它们在性能上与公共领域相同。

如果您想要一些特定的属性需要的例子,那么您无法使用常规成员变量,请考虑inheritance:如果类使用公共成员,则此类的派生无法实现validation或其他getter / setter行为。 他们坚持使用变量,如果他们想要做一些不同的事情,他们必须1)忽略现有的成员变量并创建一个新属性,2)添加一个新属性,并且3)覆盖每个方法调用或依赖成员变量来代替使用该属性。 这不仅是不必要的更多工作,如果编写派生类的人无法访问源,它几乎是不可能的。

如果基类使用属性而不是成员变量,那么只需要将validation或其他行为添加到get / set函数,您就完成了。