属性确定性

7
有没有办法在C#中将属性标记为确定性的?
我之所以这样问,是因为我经常发现自己声明了一个本地变量,并将属性读入其中,而不是多次访问该属性。
有没有办法将属性装饰为确定性,以便编译器可以优化对该属性的多次访问?我猜在这种情况下,类需要是不可变的,并且需要装饰为这样。
这是真的存在吗?还是我在做无用功?
4个回答

8
如果属性很简单,比如隐式属性:
public int X { get; set; }

或者从本地变量中读取:

public int X { get { return _x; } }

如果多次访问属性与将属性放入变量并访问该变量之间没有区别,那么编译器将优化代码。

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

通常,属性应该是轻量级的,这样每次访问它时就不必期望任何重度处理。如果获取属性的值很昂贵,则类应在内部缓存该值,以便仅在第一次读取属性时进行昂贵的操作(延迟加载模式)。

如果每次获取属性的代价很高,那么它根本不应该是一个属性,而应该是一个getter方法。


+1 - 只有一个问题 - 如果编译器已经进行了此优化,那么它将如何处理非不可变对象上的对象更改 - 无论是来自同一线程还是不同线程?如果简单属性的属性获取成本非常小,那么您是否可能只是验证了这一点,这种情况下,我应该停止对此过于苛刻? :) - Matt Whitfield
@Matt Whitfield:当代码被优化后,简单属性将被内部化。读取属性实际上不会调用属性getter来返回值,而是直接获取值,就像您在类中访问公共变量一样。在C#代码中,您可以获得面向对象编程中所需的抽象和隔离性,但在编译后的代码中,您可以获得公共变量的速度。 :) - Guffa
谢谢 - 我会接受这个答案,因为你的评论给了我在提问时所期望的理解。 - Matt Whitfield

5

在C#中没有机制允许您引入常量属性getter,即getter不会更改对象的状态。

微软文档简单建议不要在getter中引入任何副作用

It is a bad programming style to change the state of the object by using the get accessor. For example, the following accessor produces the side effect of changing the state of the object every time that the number field is accessed.

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);
    }
}

DateTime.Now是一个不改变状态但仍然改变值的属性。许多其他属性反映了可以通过除了get setter之外的其他方式更改的状态。 - Albin Sunnanbo
@Albin Sunnanbo:DateTime.Now在这里不是一个好的例子,因为它是静态的并且返回一个新的值类型。没有状态也没有值改变。问题在于OP想要一个机制,保证对同一属性的后续调用(至少在单线程环境中)产生相同的结果。 - Dirk Vollmar
+1,这会获得一票,但我真正想知道的是,如果您已经遵循了建议,是否有任何方法来迫使编译器意识到多个属性获取将返回相同的值,并因此将它们编译为如果您在相同作用域中多次使用相同的属性值,则首先声明本地变量。 - Matt Whitfield

2
我猜你正在寻找readonly,但是我不确定它与本地变量相比的性能如何。而且它仅适用于字段,而非属性。
此外,readonly并不意味着确定性。
private readonly List<string> fixedList = new List<string>();

这句话的意思是“只是表示fixedList对象不能被替换,但是其内容仍然可以被修改。”

0

除非您的属性的后备字段是readonly,否则您将如何解决线程问题?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接