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

All*_*hua 60 c# readonly private-members

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

public readonly string ProductLocation;
Run Code Online (Sandbox Code Playgroud)

public string ProductLocation
{
     get;
     private set;
}
Run Code Online (Sandbox Code Playgroud)

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

Bru*_*eis 79

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

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

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

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

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

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

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

  • 对我来说,最重要的区别是不变性属性,因为它实际上讽刺了一些语义价值. (7认同)

str*_*ius 23

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

private readonly string productLocation; 
public string ProductLocation { get { return productLocation; } } 
Run Code Online (Sandbox Code Playgroud)

这是

public string ProductLocation { get; } 
Run Code Online (Sandbox Code Playgroud)

这是只读的.仅从构造函数或内联初始化.初始化后无法编辑.(从任何地方都可以)

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

public string ProductLocation { get; private set } 
Run Code Online (Sandbox Code Playgroud)

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


Ant*_*ram 18

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

private readonly string productLocation; 
public string ProductLocation { get { return productLocation; } } 
Run Code Online (Sandbox Code Playgroud)

VS

public string ProductLocation { get; private set; }
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 请注意,`private set;`选项不是线程安全的. (3认同)

Jon*_*uis 8

第一个(使用readonly)将意味着一旦对象被实例化,对象甚至不能修改它自己的字段的值,而其他对象永远不能修改它.

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

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