如果类的只读字段不是不可变的,则它是不可变的

本文关键字:不可变 读字段 如果 | 更新日期: 2023-09-27 17:58:49

如果我有一个只有只读字段的C#类,但字段的类型不是不可变的,那么这个类被认为是不可变的吗?

这个类是不可变的吗?

public class Foo
{
    private readonly int[] _blah;
    public Foo(int[] blah)
    {
        _blah = blah;
    }
    public int[] Blah { get { return _blah; } }
}

_blah不是一成不变的,因为我可以更改数组的成员,尽管数组成员变量永远不会更改。

那么,如果一个类的字段都是只读的,那么它是不可变的吗?或者,只有当它的字段不仅是只读的而且本身也是不可变的,那么一个类是不可变吗?

如果类的只读字段不是不可变的,则它是不可变的

这将真正取决于你问谁或你的意思。有些人可能会说类本身是不可变的,因为它的直接成员是不可变。有人可能会说,类及其所有成员(及其属性等)——基本上,整个对象图——必须是不可变的,才能被认为是不可变。

  • 标记为只读的私有字段数组是不可变的,但这并不意味着不能用不同的值替换索引。解决此问题的方法是返回数组的副本或数组的枚举
  • 数组的对象可以是不可变的,也可以不是不可变的。无论你们是让它们不可变,还是返回它们的克隆,或者其他什么,这都取决于你们自己

在您的情况下,对象是整数(不可变),但数组本身不是(同样,取决于您定义的不可变)。如果你只想保证私有字段不能被更改,并且不关心索引,那么你就可以了。但是,如果要锁定索引,则需要以另一种方式公开数组。


此外,ReadOnlyCollection<T>是一个很好的收藏。它是一个集合,包含对原始集合的引用(它将其包装),因此索引不能更改。


还有,以防万一。。。对于"不可变"的实际含义,你已经有了不同的答案。

此类的实例不是不可变的,因为您可以更改它们的内容。例如foo.Blah[0] = 42;。但是,如果将Blah属性更改为IEnumerable<int>IReadOnlyList<int>,则实例将被认为是不可变的。

这个类不是不可变的,因为它可以被继承并添加其他东西。

如果它遵循三个原则,我认为它是不可变的:

  • 将字段设为只读字段
  • 提供一个公共财产获取加速器
  • 如果不再需要继承该类,请将其密封

这些并不是严格定义为不可变的硬性规则。它们只是指导方针。