Tengo una clase con dos readonly int
campos. Están expuestos como propiedades:
public class Thing
{
private readonly int _foo, _bar;
/// <summary> I AM IMMUTABLE. </summary>
public Thing(int foo, int bar)
{
_foo = foo;
_bar = bar;
}
public int Foo { get { return _foo; } set { } }
public int Bar { get { return _bar; } set { } }
}
Sin embargo, eso significa que lo siguiente es un código perfectamente legal:
Thing iThoughtThisWasMutable = new Thing(1, 42);
iThoughtThisWasMutable.Foo = 99; // <-- Poor, mistaken developer.
// He surely has bugs now. :-(
Los errores que surgen al suponer que funcionarían seguramente serán insidiosos. Claro, el desarrollador equivocado debería haber leído los documentos. Pero eso no cambia el hecho de que ningún error de compilación o tiempo de ejecución le advirtió sobre el problema.
¿Cómo se debe Thing
cambiar la clase para que los desarrolladores tengan menos probabilidades de cometer el error anterior?
¿Lanzar una excepción? ¿Usar un método getter en lugar de una propiedad?
c#
object-oriented
immutability
properties
kdbanman
fuente
fuente
Interfaces
. No estoy seguro de que sea lo que estoy haciendo.Respuestas:
¿Por qué legalizar ese código?
Saque el
set { }
si no hace nada.Así es como define una propiedad pública de solo lectura:
fuente
public int Foo { get; }
(propiedad automática con solo un captador) Pero lopublic int Foo { get; private set; }
es.Con C # 5 y antes, nos enfrentamos con dos opciones para campos inmutables expuestos a través de un captador:
readonly
para destruir la inmutabilidad. Sin embargo, creó mucho código de placa de caldera).Sin embargo, con C # 6 (disponible en VS2015, que se lanzó ayer), ahora obtenemos lo mejor de ambos mundos: propiedades automáticas de solo lectura. Esto nos permite simplificar la clase del OP para:
Las líneas
Foo = foo
yBar = bar
solo son válidas en el constructor (que logra el requisito robusto de solo lectura) y el campo de respaldo está implícito, en lugar de tener que definirse explícitamente (lo que logra el código más simple).fuente
Podrías deshacerte de los setters. No hacen nada, confundirán a los usuarios y generarán errores. Sin embargo, podría hacerlos privados y así deshacerse de las variables de respaldo, simplificando su código:
fuente
public int Foo { get; private set; }
" Esa clase ya no es inmutable porque puede cambiar por sí misma. Gracias, sin embargo!readonly
palabra clave es solo un poka-yoke, es decir, protege contra la clase que rompe la inmutabilidad en el futuro; Sin embargo, no es necesario para lograr la inmutabilidad.Dos soluciones
Simple:
No incluya setters como lo señaló David para objetos de solo lectura inmutables.
Alternativamente:
Permitir que los configuradores devuelvan un nuevo objeto inmutable, detallado en comparación con el anterior, pero proporciona un estado en el tiempo para cada objeto inicializado. Este diseño es una herramienta muy útil para la seguridad e inmutabilidad de subprocesos que se extiende sobre todos los lenguajes imperativos de OOP.
Pseudocódigo
fábrica pública estática
fuente