是否有必要将私有字段标记为只读?

本文关键字:记为 字段 只读 是否 | 更新日期: 2023-09-27 18:02:05

public class Foo
{
    private readonly Bar _bar;
}
public class Foo2
{
    private Bar _bar;
}

我不认为将其标记为只读有任何好处。它是私有的,如果我试图做一些内部修改它我是愚蠢的,因为我知道我想要我的类的行为?那么,有什么意义呢?我不认为这里有任何性能提升,所以不可能是这样。

是否有必要将私有字段标记为只读?

让编译器防止你犯傻总是好的

让编译器防止其他人愚蠢,即使他们不熟悉代码库,这是特别好的。

它还可以告诉阅读您代码的其他人该字段永远不会更改

在编写该类时,您知道希望它如何表现。

但:

  • 当你第一次写这个类的时候你可能会犯错误。
  • 你可能不记得你的意图,当你回来修改类以后。
  • 另一个程序员可能不知道你的意图,当他们修改类以后。

你的声明允许编译器验证你的意图是满足的,低成本和重复。它告诉你和其他人你的意图是什么。

你说得对,这并没有提高性能。但是,这里有关键的区别:

如果你的意图是创建一个类,你不试图修改_bar,它真的应该是一个只读字段。这里我可以看到两件事:

  1. 只读字段只能内联或在构建(安全)期间初始化。
  2. 它防止其他程序员过来想"哦,它不是只读的。我可以修改它。"
现在,如果您计划在调用另一个方法初始化它之前保持NOT为空,则NOT应该是只读的。但是,我想看看Lazy<T>

基本上,这是你的决定。如果你真的想成为ONLY修改这个类的人,我还是会说遵循这些规则。这是最好的做法。:)

只读是好的,如果你想在实例化时分配它,但不希望它是可更改的。我能想到的一个好场景可能是一个带有用户名/密码的数据库类。

public MyClass(string user, string password){
  this.username = username;
  this.password = password;
  this.connect();
}

假设连接在对象存活期间一直保持,那么存储此信息以供参考可能是有意义的,但在连接建立后防止将来的更改。

假设一个类有一个可变的T的集合,并且它有一个私有字段T[] theArray。设置类的方法有很多:

  1. 这个字段可以是一个永远不会被改变的数组的可变引用;对列表的更改可以通过以下方式完成:创建一个适当大小的新数组,将数据复制到该数组,适当地修改它,然后将对新数组的引用存储到字段中。注意,通过将数组包装在一个' ReadOnlyCollection '中,类可以廉价地暴露数组内容的只读快照;创建快照不需要复制阵列。
  2. 该字段可以是对可变数组的可变引用。大多数更新将通过改变现有数组来完成,但是超出数组末尾的更新将创建一个新的数组,其中包含从旧数组复制的元素。这就是"列表"的工作原理。注意,将数组包装在' ReadOnlyCollection '中可能会产生一些暂时表现为实时数据的只读视图的内容,但可能在将来的某个任意时间成为该时刻数据的快照。
  3. 该字段可以是对可变数组的不可变引用,如果该数组足够大,可以容纳将要添加的所有内容。对于变长列表不太可能,但在某些应用程序中,为最大项数预先指定和预先分配空间可能是合理的。在这个场景中,将数组包装在' ReadOnlyCollection '中将产生其状态的实时视图。

这三种不同的方法对线程安全等问题有不同的含义。如果将读取-复制-修改-写入序列放在Interlocked.CompareExchange循环中,则可以使第一个线程安全。最后一种方法可以通过使单个元素的写操作线程安全来实现线程安全。然而,第二种方法只能通过以下方式实现线程安全:要么让所有写操作共享一个锁,这个锁对于整个列表来说是通用的,并要求读取器仔细检查它们的操作以确保一致性,要么要求所有读写访问必须通过一个公共锁。

它是私有的,如果我试图在内部做一些事情来修改它,我是愚蠢的,因为我知道我想要我的类如何表现?

如果你是唯一一个人,在项目的历史上,曾经看过或修改源代码,你有一个完美的记忆,那么,是的。不需要注释或其他编程约定。就当牛仔吧。

否则,使用约定来(重新)强制意图是个好主意。