Si su intención es prohibir las asignaciones durante el tiempo de compilación, tendrá que ceñirse a las asignaciones del constructor y los instaladores privados. Sin embargo, tiene numerosas desventajas - que no son capaces de utilizar la nueva inicialización miembro, ni deseralization xml y etc.
Yo sugeriría algo como esto:
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 aquí es mucho más descriptivo y útil. Cuando lo pasa en otro lugar, puede crear fácilmente una versión inmutable. El código que funciona en inmutables debe tener lógica de solo lectura, por lo que no debería importar si es del mismo tipo que IssuerRecord. Creo una copia de cada campo en lugar de simplemente envolver el objeto porque aún puede cambiarse en otro lugar, pero puede no ser necesario especialmente para llamadas de sincronización secuenciales. Sin embargo, es más seguro almacenar una copia completa inmutable en alguna colección "para más tarde". Sin embargo, puede ser un envoltorio para las aplicaciones cuando desee que algún código prohíba las modificaciones pero aún así tenga la capacidad de recibir actualizaciones del estado del objeto.
var record = new IssuerRecord { PropA = "aa" };
if(!Verify(new ImmutableIssuerRecord(record))) return false;
si se piensa en términos de C++, se puede ver ImmutableIssuerRecords como "IssuerRecord const". Sin embargo, debe tener cuidado extra para proteger objetos que son propiedad de su objeto inmutable, por eso sugiero crear una copia para todos los niños (ejemplo de Subrecords).
ImmutableIssuerRecord.Subrecors es IEnumerable aquí y carece de Count y esto [], pero IReadOnlyList viene en 4.5 y puede copiarlo de docs si lo desea (y facilitar la migración posterior).
hay otros enfoques, así como congelar:
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; }
}
código que hace menos legible de nuevo, y no proporciona protección en tiempo de compilación. pero puedes crear objetos como normales y luego congelarlos cuando estén listos.
El patrón de generador también es algo a tener en cuenta, pero agrega demasiado código de "servicio" desde mi punto de vista.
¿Necesita algo externo a la clase establecer los valores, o puede la clase misma establecer los valores? Si la clase puede hacerlo, entonces puede tener un constructor sin parámetros. –
Ver: http://stackoverflow.com/questions/355172/how-to-design-an-immutable-object-with-complex-initialization?rq=1 – aquinas
¿Cómo está inicializando estas propiedades ahora? –