2010-09-15 40 views
7

C#中是否有任何方法将属性标记为确定性?属性决定论

我问的原因是我经常发现自己声明了一个局部变量并读入一个属性,而不是多次访问属性。

是否有任何方法可以将属性修饰为确定性,以便编译器可以优化对该属性的多次访问?我猜在这种情况下,班级需要是不可改变的,并且是这样装饰的。

这是甚至存在的东西还是我抓着吸管?

回答

7

如果属性是简单,像一个隐含的属性:

​​

或从本地变量读取:

public int X { get { return _x; } } 

则编译器将优化代码,以便有没有区别多次访问该属性并将该属性放入一个变量并访问该属性。

我通过比较访问属性十次并将属性复制到一个变量并访问十次来验证这一点,并且根本没有可测量的差异。

一般属性应该是轻量级的,这样您就不必期望每次访问时都有大量的处理。如果该属性的值成本高昂,则该类应在内部缓存该值,以便读取该属性只会首次执行代价高昂的操作(延迟加载模式)。

如果一个属性花费很多时间,它不应该是一个属性,而是一个getter方法。

+0

+1 - 只有一个问题 - 如果编译器确实做了这种优化,那么它将如何解释非不可变对象上的对象的变化 - 无论它是否来自同一个线程?您是否有可能验证该房产获得的房产价格非常低,在这种情况下,我应该停止对此进行肛门分析? :) – 2010-09-15 09:12:44

+0

@Matt Whitfield:当代码被优化时,简单的属性将被实现。读取该属性实际上不会调用属性getter来返回值,而是直接获取该值,就像访问类中的公共变量一样。在C#代码中,您可以在OOP代码中获得所需的抽象和隔离,但在编译代码中,您可以获得公共变量的速度。 :) – Guffa 2010-09-15 09:24:12

+0

谢谢 - 我打算接受这个,因为你在那里的评论有点让我理解当我问这个问题时我正在寻找的理解。 – 2010-09-15 09:26:13

0

除非你的财产的支持字段是readonly,你将如何解决线程问题?

5

C#中没有任何机制允许您引入const属性getter,即不改变对象状态的getter。

微软文件只是建议not to introduce any side-effects在干将:

这是一个不好的编程风格使用get访问来改变对象的状态。例如,以下访问器每次访问数字字段时都会产生更改对象状态的副作用。

private int number; 
public int Number 
{ 
    get 
    { 
     return number++; // Don't do this 
    } 
} 

正如达人所提到的,另一个方面要考虑的是多线程(除非你的对象是真正的不可变的)。如果另一个线程改变了对象的状态,这样getter应该在第二次调用时返回一个不同的值呢?编译器没有简单的方法来保证,例如在下面的场景:

class List 
{ 
    IList data; 

    // called several times on thread A 
    // property has no side-effects 
    public int Count { get data.Length; } 

    // called several times on thread B 
    public void Add(object o) 
    { 
     data.Add(o); 
    } 
} 
+0

DateTime.Now是一个不会改变状态但改变值的属性。许多其他属性反映的状态可以通过其他方式进行更改,而不仅仅是get setter。 – 2010-09-15 09:01:53

+0

@Albin Sunnanbo:'DateTime.Now'在这里不是一个好的例子,因为它是静态的,它*返回一个新的值类型。没有状态或价值改变。问题在于OP希望有一种机制保证后续调用相同的属性(至少在单线程环境中)会产生相同的结果。 – 2010-09-15 09:07:05

+0

+1,这肯定会得到一票,但我真正想知道的是,如果你遵循了这些建议,是否有办法强制编译器意识到多个属性获取将返回相同的值,因此如果您在同一个作用域中多次使用相同的属性值,那么先编译它们就好像您先声明了一个局部变量。 – 2010-09-15 09:08:27

2

我猜你正在寻找readonly,但我不知道性能如何比较的局部变量。它只适用于字段,而不适用于属性。

除了readonly并不意味着决定论。

private readonly List<string> fixedList = new List<string>(); 

只是意味着fixedList对象不能被替换,但内容仍然可以改变。