L'immutabilità non è un obiettivo finale, di per sé. L'immutabilità è uno strumento. Come tutti gli strumenti, ha i suoi usi appropriati, i suoi vantaggi e svantaggi. Raggiungerlo con oggetti mutabili esistenti è più difficile di quanto sembri.
Considera un array ordinario:
var pokerHand = new Cards[5];
Possiamo creare una struttura dati usando un array come backing field e scrivendo un indicizzatore per questo:
public class ImmutableArray<T>
{
T[] array;
public this T(int index)
{
get { return array[index]; }
}
}
Eliminando il setter dall'indicizzatore, hai effettivamente reso immutabile l'accesso ai membri, giusto? Bene, non esattamente. Poiché l'elemento restituito dall'indicizzatore è un tipo di riferimento, puoi comunque sostituire l'oggetto detenuto da quel tipo di riferimento e ora hai un nuovo oggetto in quella posizione nell'array.
var item = myPokerHand[5];
item = new Card("KS"); // myPokerHand[5] now contains a new Card
Per proteggere il contenuto dell'array originale, devi fare una copia dell'oggetto e restituirlo.
public this T(int index)
{
get { return array[index].MemberwiseClone(); } // if you can.
}
Tieni presente che MemberwiseClone è un copia superficiale , non una copia profonda. Fare questo correttamente potrebbe significare scrivere un metodo Clone che copia fedelmente tutti i membri del tuo oggetto, alcuni dei quali potrebbero anche essere riferimenti mutevoli.
Per tutti questi motivi, è meglio utilizzare le raccolte immutabili già fornite dal framework .NET, come ReadOnlyCollection , raccolte progettate da zero per essere immutabili.
Per le proprie collezioni e oggetti, la limitazione periodica dell'accesso ai membri privati è generalmente una buona cosa, per ragioni che spero siano ovvie (cfr. incapsulamento).
Ulteriori letture
Immutabilità in C # prima parte: tipi di immutabilità