readonly修饰符和私有setter之间哪个更好?

时间:2011-11-02 03:55:41

标签: c# readonly private-members

我一直在努力创建一个课程,突然想到了两个代码之间有什么区别的想法:

public readonly string ProductLocation;

public string ProductLocation
{
     get;
     private set;
}

你能告诉我什么时候更好地使用以下内容吗?感谢。

5 个答案:

答案 0 :(得分:67)

第一个是只读字段,而第二个被编译为一对方法(并且属性ProductLocation的所有读取都被编译为对相应get方法的调用,对它的写入被编译成对set方法的调用;在内部,这些方法将读取/写入内部的,自动生成的非只读字段。 我说最重要的区别是线程安全性! (怎么样?继续阅读!)

该类的基本用法看起来完全相同:其他类中的代码只能读取值,而不能更改它。此外,读取值的代码看起来完全相同(例如,print(myInstace.ProductLocation);在这里,你不知道它是如何声明的,很酷,是吗?)

第一个,最微不足道的区别是具有私有setter的属性允许同一个类的实例修改该值,而在rea​​donly属性的情况下,甚至对象本身都不能更改该值。

现在,对于线程安全性。当您使用多个线程时,该字段上的readonly属性将更改其内存可见性语义(就像Java的final一样字段)。

readonly字段只能在声明或构造函数中指定。 分配给readonly字段的值无法更改(至少不能以正常方式),并且保证每个线程都会在构造函数后看到正确的初始化值返回即可。因此,readonly字段本质上是线程安全的。

要实现与属性相同的线程安全性,您必须在代码上添加一些同步,这很容易出错。根据具体情况,它可能导致死锁,数据竞争或性能下降,特别是如果您没有经验。

因此,如果值表示在对象构造之后无法更改语义的内容,则不应声明私有setter(这意味着该对象可能会更改它)。去readonly字段(并且可能声明它是私有的并声明一个只有getter访问字段的公共属性!这实际上是首选形式,因为暴露字段不好,最好只暴露方法 - 那里解释为什么在this answer

中有很多原因

答案 1 :(得分:21)

使用C# 6.0 自动属性初始化程序,可以减少样板操作

private readonly string productLocation; 
public string ProductLocation { get { return productLocation; } } 

哪个是

public string ProductLocation { get; } 

这是只读的。仅从构造函数或内联初始化。初始化后无法编辑。 (随处可见)

但是,如果您使用私人套装;

public string ProductLocation { get; private set } 

这是从外面读取的。但是可以在类本身的任何地方随时初始化。并且可以通过类本身在其生命周期内进行编辑。 (从课堂变化,从外部不变)

答案 2 :(得分:18)

通常,.NET不鼓励公开公开成员字段,这些字段应该由属性包装。所以我们假设你可能有

private readonly string productLocation; 
public string ProductLocation { get { return productLocation; } } 

vs

public string ProductLocation { get; private set; }

在这个设置中,忽略了人们可以通过反射完成的事情,语义是在第一种情况下,productLocation变量只能在适当的位置和类构造函数中初始化。班上的其他成员不能改变价值。外部消费者无法设定价值。

在第二个版本中,外部消费者继续无法设置价值。但是,类本身可以随时更改值。如果您拥有的只是一个DTO(即,只传输数据的类,它没有通过方法表达的逻辑),那么这与readonly版本基本上没有什么不同。但是,对于具有方法的类,这些方法可能会改变ProductLocation后面的值。

如果要在构造后强制执行不可变字段的概念,请使用readonly。但对于DTO,我可能会选择private set;选项,主要是因为它的样板代码较少。

答案 3 :(得分:8)

第一个(使用readonly)意味着对象甚至无法修改自己的字段值,一旦对象被实例化,其他人永远无法修改它。

第二个(使用private set)意味着对象可以在实例化后修改其字段的值,但其他人永远不能修改它。

我会将前者用于你知道不会改变的东西,并将后者用于价值可能改变的东西,但你不希望别人改变它。

答案 4 :(得分:4)

第一个是字段,其值只能在实例化时设置

第二个是属性,其值可以随时设置(但仅限于其包含的对象)。


更正:属性可以由任何同一类的实例随时设置(而不仅仅是由其包含的对象)。