财产决定论

时间:2010-09-15 08:49:52

标签: c# properties deterministic

C#中有没有办法将属性标记为确定性?

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

有没有什么方法可以将属性装饰为确定性的,这样编译器就可以优化对该属性的多次访问?我在这样的场景中猜测,这个类需要是不可变的,并且这样装饰。

这是甚至存在的东西,还是我抓着稻草?

4 个答案:

答案 0 :(得分:8)

如果属性很简单,就像隐式属性一样:

public int X { get; set; }

或从本地变量读取:

public int X { get { return _x; } }

然后编译器将优化代码,以便多次访问属性和将属性放入变量并访问它之间没有区别。

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

一般来说,属性应该是轻量级的,这样您每次访问它时都不必期望任何繁重的处理。如果属性的值很昂贵,那么类应该在内部缓存该值,以便读取属性只会使第一次进行昂贵的操作(延迟加载模式)。

如果每次获得一个属性成本高昂,它根本不应该是一个属性,而是一个getter方法。

答案 1 :(得分:5)

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

Microsoft文档只是在getter中推荐not to introduce any side-effects

  

使用get访问器更改对象的状态是一种糟糕的编程风格。例如,以下访问器产生每次访问数字字段时更改对象状态的副作用。

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

如Daren所述,要考虑的另一个方面是多线程(除非你的对象真的是不可变的)。如果另一个线程更改了对象状态,以便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);
    }
}

答案 2 :(得分:2)

我猜你正在寻找readonly,但是我不确定如何将性能与局部变量进行比较。它仅适用于字段,而不适用于属性。

此外readonly并不意味着决定论。

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

只是意味着无法替换fixedList对象,但仍可以更改内容。

答案 3 :(得分:0)

除非您的财产的支持字段为readonly,否则您将如何解决线程问题?