如何创建不可变类?

Bis*_*ath 108 .net c# immutability

我正在创建一个不可变的类.
我已将所有属性标记为只读.

我有一个课程列表.
虽然如果属性是只读的,则可以修改列表.

公开列表的IEnumerable使其不可变.
我想知道为了使一个类不可变而必须遵循的基本规则是什么?

Bla*_*rad 117

我认为你走在正确的轨道上 -

  • 注入到类中的所有信息都应该在构造函数中提供
  • 所有属性应该只是getter
  • 如果将一个集合(或数组)传递给构造函数,则应该将其复制以防止调用者以后修改它
  • 如果你要返回你的集合,要么返回一个副本或只读版本(例如,使用ArrayList.ReadOnly或类似的东西 - 你可以将它与前一个点结合起来并存储一个只读副本,当它返回时调用者访问它,返回枚举器,或使用允许对集合进行只读访问的其他方法/属性
  • 请记住,如果您的任何成员是可变的,您仍然可能具有可变类的外观 - 如果是这种情况,您应该复制掉您想要保留的任何状态并避免返回整个可变对象,除非您复制它们在将它们交还给调用者之前 - 另一个选择是只返回可变对象的不可变"部分" - 感谢@Brian Rasmussen鼓励我扩展这一点

  • 应复制作为参数传递给构造函数的任何可变引用类型.否则呼叫者仍将保持对州的引用. (5认同)

Joe*_*Joe 17

要成为不可变的,所有属性和字段都应该是只读的.任何列表中的项目本身都应该是不可变的.

您可以按如下方式创建只读列表属性:

public class MyClass
{
    public MyClass(..., IList<MyType> items)
    {
        ...
        _myReadOnlyList = new List<MyType>(items).AsReadOnly();
    }

    public IList<MyType> MyReadOnlyList
    {
        get { return _myReadOnlyList; }
    }
    private IList<MyType> _myReadOnlyList

}
Run Code Online (Sandbox Code Playgroud)


lub*_*sko 11

另外,请记住:

public readonly object[] MyObjects;
Run Code Online (Sandbox Code Playgroud)

即使用readonly关键字标记,也不是不可变的.您仍然可以通过索引访问器更改单个数组引用/值.


KUT*_*ime 8

您所需要的只是 L...EhmrecordC# 9.0或更高版本。

public record Customer(string FirstName, string LastName, IEnumerable<string> Items);

//...

var person = new Customer("Test", "test", new List<string>() { "Test1", "Test2", "Test3" });
// you can't change anything within person variable
// person.FirstName = "NewName";
Run Code Online (Sandbox Code Playgroud)

这被转换为名为 Customer 的不可变类,具有三个属性FirstNameLastNameItems

如果您需要一个不可变(只读)集合作为类的属性,最好将其公开为IEnumerable<T>ReadOnlyCollection<T>比以下内容更好:System.Collections.Immutable


mbi*_*ard 5

使用ReadOnlyCollection类。它位于System.Collections.ObjectModel命名空间中。

在返回列表的任何内容上(或在构造函数中),将列表设置为只读集合。

using System.Collections.ObjectModel;

...

public MyClass(..., List<ListItemType> theList, ...)
{
    ...
    this.myListItemCollection= theList.AsReadOnly();
    ...
}

public ReadOnlyCollection<ListItemType> ListItems
{
     get { return this.myListItemCollection; }
}
Run Code Online (Sandbox Code Playgroud)