Se l'intento è vietare le assegnazioni durante il tempo di compilazione, è necessario attenersi alle assegnazioni del costruttore e ai setter privati. Tuttavia ha numerosi svantaggi - non sono in grado di utilizzare la nuova inizializzazione di membri, né xml deseralization ed ecc
Vorrei suggerire qualcosa di simile:
public class IssuerRecord
{
public string PropA { get; set; }
public IList<IssuerRecord> Subrecords { get; set; }
}
public class ImmutableIssuerRecord
{
public ImmutableIssuerRecord(IssuerRecord record)
{
PropA = record.PropA;
Subrecords = record.Subrecords.Select(r => new ImmutableIssuerRecord(r));
}
public string PropA { get; private set; }
// lacks Count and this[int] but it's IReadOnlyList<T> is coming in 4.5.
public IEnumerable<ImmutableIssuerRecord> Subrecords { get; private set; }
// you may want to get a mutable copy again at some point.
public IssuerRecord GetMutableCopy()
{
var copy = new IssuerRecord
{
PropA = PropA,
Subrecords = new List<IssuerRecord>(Subrecords.Select(r => r.GetMutableCopy()))
};
return copy;
}
}
IssuerRecord qui è molto più descrittivo e utile. Quando lo passi da qualche altra parte, puoi facilmente creare una versione immutabile. Il codice che funziona su immutabile dovrebbe avere una logica di sola lettura, quindi non dovrebbe importare se è lo stesso tipo di IssuerRecord. Creo una copia di ogni campo invece di semplicemente avvolgere l'oggetto perché potrebbe ancora essere cambiato da qualche altra parte, ma potrebbe non essere necessario in particolare per le chiamate di sincronizzazione sequenziali. Tuttavia è più sicuro conservare la copia completa e immutabile in alcune raccolte "per dopo". Può essere un wrapper per le applicazioni quando si desidera che alcuni codici proibiscano le modifiche ma hanno ancora la possibilità di ricevere aggiornamenti allo stato dell'oggetto.
var record = new IssuerRecord { PropA = "aa" };
if(!Verify(new ImmutableIssuerRecord(record))) return false;
se si pensa in termini C++, si può vedere come ImmutableIssuerRecords "IssuerRecord const". Devi prendere extracare anche se per proteggere gli oggetti che sono di proprietà del tuo oggetto immutabile è per questo che suggerisco di creare una copia per tutti i bambini (esempio Subrecords).
ImmutableIssuerRecord.Subrecors è IEnumerable qui e manca il conte e questo [], ma IReadOnlyList è venuta a 4.5 ed è possibile copiarlo da docs se voleva (e rendere più facile la migrazione in seguito).
ci sono altri approcci come pure, come ad esempio Freezable:
public class IssuerRecord
{
private bool isFrozen = false;
private string propA;
public string PropA
{
get { return propA; }
set
{
if(isFrozen) throw new NotSupportedOperationException();
propA = value;
}
}
public void Freeze() { isFrozen = true; }
}
che rende il codice meno leggibile di nuovo, e non fornisce una protezione in fase di compilazione. ma puoi creare oggetti come normali e poi congelarli dopo che sono pronti.
Il modello di generatore è anche qualcosa da considerare, ma aggiunge troppo codice di "servizio" dal mio punto di vista.
Qualcosa di esterno alla classe ha bisogno di impostare i valori o può la classe stessa impostare i valori? Se la classe può farlo, allora puoi avere un costruttore senza parametri. –
Vedere: http://stackoverflow.com/questions/355172/how-to-design-an-immutable-object-with-complex-initialization?rq=1 – aquinas
Come si stanno inizializzando queste proprietà ora? –