martes, 27 de junio de 2017
Compartir:
En realidad no es algo demasiado diferente a lo que hacemos normalmente cuando almacenamos en una variable local el resultado de un método que retorna un único valor:
// Guardamos el valor de retorno en variable local var sum = Sum(1, 3); Console.WriteLine($"Sum: {sum}"); ... static int Sum(int a, int b) { return a+b; }
Pues bien, cuando un método retorna más de un valor en forma de tupla, podemos conseguir exactamente lo mismo para todos los valores retornados, de una forma igualmente sencilla. El siguiente ejemplo muestra un método que retorna una tupla, y cómo la deconstruimos para obtener sus valores en forma de nuevas variables locales:
// Guardamos los valores de retorno en variables locales var (add, sub, mul, div) = Calculate(1, 3); Console.WriteLine($"Sum: {add}"); ... static (int add, int sub, int mul, int div) Calculate(int a, int b) { return (a + b, a - b, a * b, a / b); }Observad que hemos utilizado la palabra clave
var
para indicar al compilador que sea él el que se encargue de inferir los tipos de los elementos de la tupla. Pero si nos va el masoquismo podríamos hacerlo de forma mucho más trabajosa; las siguientes líneas son equivalentes:(int add, int sub, int mul, int div) = Calculate(1, 3); (var add, var sub, var mul, var div) = Calculate(1, 3); var (add, sub, mul, div) = Calculate(1, 3);También podemos deconstruir sobre variables existentes con anterioridad, como en el siguiente ejemplo:
int add, sub, mul, div; ... (add, sub, mul, div) = Calculate(1, 3); Console.WriteLine($"Sum: {add}");Por supuesto, los nombres de las variables locales pueden ser diferentes a los nombres asignados a los miembros de la tupla. Lo que importa es el orden, que sí debe coincidir (¡recordad que una tupla es una lista ordenada de elementos!):
var (a, s, m, d) = Calculate(1, 3); Console.WriteLine($"Sum: {a}");Otro aspecto interesante es que si, como en el ejemplo anterior, no vamos a utilizar todos los elementos de la tupla, podemos sustituir por el placeholder "_" los elementos que no nos interesen:
var (add, _, _, div) = Calculate(1, 3); Console.WriteLine($"Sum: {add}, Div: {div}");
La deconstrucción más allá de las tuplas
Aunque hemos visto la deconstrucción en el ámbito de las tuplas, donde tienen una aplicación sencilla y directa, en realidad es una característica del lenguaje que puede utilizarse con cualquier tipo de .NET. No veo que sea algo excesivamente útil en la práctica, e incluso dudo mucho que favorezca la legibilidad del código, pero bueno, siempre es bueno saber que existe esta posibilidad y cómo implementarla.Para que un tipo cualquiera (clase o estructura) pueda ser deconstruido, debe implementar un método
void
llamado Deconstruct()
, más o menos con la siguiente pinta:class Person { public string Name { get; set; } public int Age { get; set; } public string Email { get; set; } public void Deconstruct(out string name, out int age, out string email) { name = Name; age = Age; email = Email; } }El número y tipo de parámetros
out
en Deconstruct()
es el que define las "piezas" en las que podrán ser deconstruidos los objetos de nuestra clase. Así, según el código anterior, podríamos efectuar una deconstrucción de la siguiente manera:var person = _myServices.GetPersonById(3422); ... var (name, age, email) = person; Console.WriteLine($"I'm {name}, {age} years old"); Console.WriteLine($"Contact me at {email}");De hecho, si descompilamos un código como el visto anteriormente, descubriremos que, al fin y al cabo, la deconstrucción es un simple edulcorante sintáctico sobre las llamadas al método
Deconstruct()
:// Decompiled sources: string name; string email; int age; person.Deconstruct(out name, out age, out email);Por este motivo, en la práctica es posible crear distintas sobrecargas de
Deconstruct()
que serán invocadas en función del número de parámetros que utilicemos en la deconstrucción:class Person { public string Name { get; set; } public int Age { get; set; } public string Email { get; set; } // Consumo: var (name, age) = person; public void Deconstruct(out string name, out int age) { name = Name; age = Age; } // Consumo: var (name, age, email) = person; public void Deconstruct(out string name, out int age, out string email) { name = Name; age = Age; email = Email; } }En definitiva, tenemos delante una vuelta de tuerca al lenguaje que permite sacar mayor partido a las tuplas y facilita la codificación en algunos escenarios. Aunque probablemente no vayamos a usarla todos los días, sin duda es una herramienta interesante para tener en nuestro cinturón de herramientas.
Por último, por si os interesa, os recuerdo otros posts de esta serie sobre novedades de C# 7:
Publicado en Variable not found.
Aún no hay comentarios, ¡sé el primero!
Enviar un nuevo comentario
Backlinks: