¿Cómo creo una clase inmutable?

Estoy trabajando en crear una clase inmutable.
Marqué todas las propiedades como de solo lectura.

Tengo una lista de artículos en la clase.
Aunque si la propiedad es de solo lectura, la lista se puede modificar.

Exponer el IEnumerable de la lista lo hace inmutable.
Quería saber cuáles son las reglas básicas que uno debe seguir para que una clase sea inmutable.

Creo que estás en el camino correcto

  • toda la información inyectada en la clase debe ser suministrada en el constructor
  • todas las propiedades deben ser solo getters
  • si una colección (o matriz) se pasa al constructor, debe copiarse para evitar que la persona que llama modifique más tarde
  • si va a devolver su colección, devuelva una copia o una versión de solo lectura (por ejemplo, usando ArrayList.ReadOnly o similar, puede combinar esto con el punto anterior y almacenar una copia de solo lectura para devolver cuando las personas que llaman acceden a él), devuelven un enumerador o utilizan algún otro método / propiedad que permite el acceso de solo lectura a la colección
  • tenga en cuenta que puede tener la apariencia de una clase mutable si alguno de sus miembros es mutable; si este es el caso, debe copiar cualquier estado que quiera conservar y evitar devolver objetos mutables enteros, a menos que los copie antes de devolvérselos a la persona que llama – otra opción es devolver solo “secciones” inmutables del objeto mutable – gracias a @Brian Rasmussen por animarme a expandir este punto

Para ser inmutable, todas sus propiedades y campos deben ser de solo lectura. Y los elementos en cualquier lista deberían ser inmutables.

Puede hacer una propiedad de lista de solo lectura de la siguiente manera:

public class MyClass { public MyClass(..., IList items) { ... _myReadOnlyList = new List(items).AsReadOnly(); } public IList MyReadOnlyList { get { return _myReadOnlyList; } } private IList _myReadOnlyList } 

Además, tenga en cuenta que:

 public readonly object[] MyObjects; 

no es inmutable, incluso si está marcado con la palabra clave readonly. Aún puede cambiar referencias / valores de matriz individuales por acceso de índice.

Use la clase ReadOnlyCollection . Está situado en el espacio de nombres System.Collections.ObjectModel .

En cualquier cosa que devuelva su lista (o en el constructor), establezca la lista como una colección de solo lectura.

 using System.Collections.ObjectModel; ... public MyClass(..., List theList, ...) { ... this.myListItemCollection= theList.AsReadOnly(); ... } public ReadOnlyCollection ListItems { get { return this.myListItemCollection; } } 

Otra opción sería usar un patrón de visitante en lugar de exponer cualquier colección interna.