Objetos y propiedades inmutables en C#
Cuando programamos en C#, podemos crear objetos y propiedades inmutables.
De hecho, crear en C# una propiedad inmutable, es realmente sencillo.
Pero me he dado cuenta que muchos programadores de C# no saben crear y diferenciar bien entre un objeto inmutable y una propiedad inmutable.
Así que me he decidido a escribir una pequeña entrada en mi blog que lo resuma de forma rápida y sencilla.
Un objeto inmutable (immutable type), es aquel cuyo estado, valores, sólo pueden ser establecidas en la inicialización del mismo.
Una vez que un objeto es creado, no puede cambiar nada del mismo.
Del mismo modo, cuando hablamos de propiedades inmutables en C#, lo que estamos indicando es que son propiedades de sólo lectura.
Esta es… la teoría.
Pero veamos todo esto con ejemplos.
Una propiedad inmutable, podría ser la siguiente:
private readonly string _name; public string Name { get { return _name; } }
Pero C# nos ofrece otra forma más simple de hacer lo mismo:
private readonly string _name; public string Name => _name;
Estas instrucciones (equivalentes entre sí), no es otra cosa que una propiedad pública de sólo lectura y una propiedad privada de sólo lectura.
De esta manera y para este ejemplo, aseguraremos la inmutabilidad de la propiedad.
Cuando hablamos de objetos inmutables, lo que hacemos no es otra cosa que ampliar el concepto que acabamos de ver.
Extendamos por lo tanto estos conocimientos a los objetos que creemos.
Lo mejor, es ver esto con un ejemplo, así que supongamos la siguiente clase:
public class ImmutableObject { private readonly string _name; public string Name => _name; public ImmutableObject(string name) { _name = name; } }
En este caso, hemos creado un objeto inmutable.
Si queremos cambiar el valor de Name dentro de la clase, tendremos que destruir el objeto existente y crear un objeto nuevo, por lo que el objeto que teníamos antes (inmutable), dejaría de existir para crear uno nuevo objeto (inmutable).
Pero como todo en la vida, podemos encontrarnos con situaciones concretas en las que rompamos esta inmutabilidad, y quiero compartir esto para abrir un poco la mente para que tengamos en cuenta posibles puertas traseras.
Supongamos la siguiente clase:
public class MyClass { public string Name { get; set; } public ImmutableObject MyObject => new ImmutableObject(Name); }
Puedo declarar mi clase de la siguiente manera:
MyClass myClass = new MyClass() { Name = "John" }; Console.WriteLine(myClass.MyObject.Name);
Como resultado, obtendré: «John«.
Ahora bien, como es lógico, no podría hacer esto:
myClass.MyObject.Name = "Mary";
Ya que tendríamos un error en tiempo de codificación, indicándonos con buen criterio, que Name es de sólo lectura.
Sin embargo, sí podríamos saltarnos esta norma haciendo lo siguiente:
myClass.Name = "Lewis";
En cuyo caso, obtendríamos como salida: «Lewis«.
Con lo que perdemos la idea de inmutabilidad directa e inicial del objeto MyObject que tenemos dentro de MyClass.
El hecho de que Name no sea inmutable en MyClass, y sea referenciado en ImmutableObject, produce este problema.
Para evitar este problema, volvemos a tener la necesidad de hacer inmutable a MyClass de la forma:
public class MyClass { private readonly string _name; public MyClass(string name) { _name = name; } public ImmutableObject MyObject => new ImmutableObject(_name); }
Por último, comentar que hablando de concurrencia, las clases inmutables tienen una ventaja respecto a las clases que no lo son.
Al ser sus propiedades inmutables, no debemos realizar ningún tipo de sincronización ni tener ningún cuidado adicional a la hora de acceder a sus valores.
El único matiz a tener en cuenta es que manejemos adecuadamente la inmutabilidad para no tener sorpresas como he demostrado.
¡Happy Coding!