¿Qué son los deconstructores en C# y para qué sirven?

13/01/2022Artículo original

Un deconstructor es una forma de transformar una tupla o un objeto en diferentes variables, de forma que dejen de trabajar de manera agrupada. Es decir, nos permite controlar con exactitud cómo podemos “mapear” una tupla o las propiedades de un objeto hacia diferentes variables.

Para ilustrarlo pensemos en un método que devuelve una tupla con dos elementos: nombre y apellidos.

public (string nombre, string apellido) ObtenerDatos(){ return ("Rubén", "Rubio");}

Hasta este momento, si obtenemos el valor devuelto por el método e intentamos mostrarlo por consola, tendríamos que realizar algo como lo siguiente:

var tuplaDesdeMetodo = ObtenerDatos();Console.WriteLine($"Usuario: {tuplaDesdeMetodo.nombre} {tuplaDesdeMetodo.apellido}");

Pero no tendríamos forma de manejar nombre y apellidos como variables independientes, puesto que es una tupla. Pues precisamente, eso es lo que nos va a permitir la deconstrucción, es decir, que cada elemento pase a una variable independiente.

Para eso tendremos dos opciones:

  1. Declarar explícitamente el tipo de cada variable.
  2. Emplear la palabra reservada var y realizar una declaración implícita.

Por lo tanto podríamos hacer lo siguiente:

// Con declaración explícita(string nombreExplicito, string apellidoExplicito) = ObtenerDatos();Console.WriteLine($"Usuario con declaración explícita: {nombreExplicito} {apellidoExplicito}");// Con declaración implícitavar (nombreImplicito, apellidoImplicito) = ObtenerDatos();Console.WriteLine($"Usuario con declaración implícita: {nombreImplicito} {apellidoImplicito}");

Como podemos observar, de cualquier manera que lo hagamos, el uso posterior es como si se tratase de variables independientes, siendo el siguiente el resultado de la ejecución:

  Aprender programación con apuntes hechos a mano y explicaciones usando gatitos es la propuesta de estas desarrolladoras argentinas

Pero, inicializar variables nuevas para almacenar los valores obtenidos no es la única opción; también podremos realizar una asignación a variables previamente declaradas.

El siguiente código es equivalente al ejemplo anterior, con la salvedad que en esta ocasión el deconstructor realiza una asignación a variables ya existentes:

string nombre = "";string apellido = "";(nombre, apellido) = ObtenerDatos();Console.WriteLine($"Usuario con asignación: {nombre} {apellido}");

Otra posibilidad, disponible con C# 10 o posterior, es la capacidad de mezclar ambas opciones. Es decir, por un lado tendremos valores almacenados mediante la inicialización de variables, mientras que por otro estaremos realizando una asignación en variables preexistentes:

string nombre = "";(nombre, string apellido) = ObtenerDatos();Console.WriteLine($"Usuario con asignación y declaración: {nombre} {apellido}");

Deconstrucción en nuestras propias clases

Si queremos ir más allá de las tuplas y dotar de esta capacidad de deconstrucción a nuestras propias clases, también podemos hacerlo. Para eso bastará con añadir un método llamado Deconstruct que no devuelva nada (void). Además, tendrá “n” parámetros de tipo out, que serán los que devuelvan los valores.

Tomemos como ejemplo una clase Alumno con dos propiedades: Nombre y Apellidos. Bastaría con añadir un método Deconstruct quedando como sigue:

public class Alumno{ public string Nombre { get; set; } public string Apellidos { get; set; } public void Deconstruct(out string nombre, out string apellido) { nombre = Nombre; apellido = Apellidos; }}

Posteriormente, si declaramos un objeto de tipo Alumno, podremos llevar a cabo la deconstrucción, obteniendo en este caso dos variables con el nombre y el apellido que contiene el objeto:

Alumno alumno = new Alumno(){ Nombre = "Rubén", Apellidos = "Rubio"};var (nombre, apellido) = alumno;Console.WriteLine($"Alumno deconstruído: {nombre} {apellido}");

  ¿Qué es un ORM?

Esto es muy útil en ocasiones porque nos permite deestructurar objetos de manera directa, con solo asignarlos, gracias a la deconstrucción.

Deconstrucción de clases ajenas mediante métodos de extensión

Pero ¿qué ocurre en el caso de que nos interese poder deconstruir de esta manera una clase que no sea nuestra, o sea de la que no tengamos acceso a modificar su código?

Por suerte podemos utilizar métodos de extensión, como en otros tantos sitios de la plataforma, para lograr el mismo resultado. En este caso creamos el método extensor Deconstruct tomando como primer parámetro una clase que nos interesa, de la manera convencional para este tipo de métodos.

Por ejemplo, para deconstruir objetos de la clase DateOnly y obtener sus miembros de manera independiente, podemos crear el siguiente método de extensión:

public static class Deconstructores{ public static void Deconstruct(this DateOnly fecha, out int anho, out int mes, out int dia) { anho = fecha.Year; mes = fecha.Month; dia = fecha.Day; }}

Ahora podríamos utilizarlo de manera directa, así:

DateOnly elFuturo = new(2099,5,23);(int anhoFuturo, int mesFuturo, int diaFuturo) = elFuturo;Console.WriteLine($@"El año del futuro es {anhoFuturo}, en el mes {mesFuturo}, con el día {diaFuturo}");

que nos devolvería por pantalla la cadena:

El año del futuro es 2099,en el mes 5,con el día 23
  RGPD / GDPR: guía práctica de protección de datos para programadores

Relacionados

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Contiene enlaces a sitios web de terceros con políticas de privacidad ajenas que podrás aceptar o no cuando accedas a ellos. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad