Es muy común que estemos realizando un proceso o servicio y tengamos que devolver de un método múltiples resultados.
Una práctica muy común es crear una clase privada la cual se va a utilizar únicamente en ese método, por lo que puede no ser la mejor solución.
Para solucionar este problema en .NET disponemos de las Tuplas, la cuales están disponibles desde .NET Framework 4.0, pero, pese a ser muy útiles, muchos desarrolladores no saben ni que existen.
Posteriormente veremos una mejora de la misma, con ValueTuple
.
1 - Qué es una Tupla?
Cuando nos referimos a una Tupla nos estamos refiriendo a una estructura de datos la cual puede contener múltiples tipos.
Como he explicado, es ideal para cuando queremos mantener múltiples datos pero no queremos crear una clase únicamente por ello.
La sintaxis de una Tupla
es la siguiente:
Tuple<T1>
...
Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>
Como podemos observar el límite de elementos es de 8, además es inmutable.
A primera vista puede parecer similar al tipo dynamic pero a diferencia de este, en la tupla tenemos nuestro tipo fuertemente tipado.
Finalmente indicar que la tupla es un reference type, por lo que se ubica en el heap.
1.1 - Crear una tupla en C#
En C# podemos crear tuplas de dos maneras:
A. Especificando los tipos genéricos en el constructor
Tuple<string, string, int> coche
= new Tuple<string, string, int>("Audi", "A3", 2008);
B. Utilizando el método estático Create
que nos proporciona C#, el cual nos permite no tener que indicar los tipos de la tupla, ya que puede ser algo tedioso si tenemos varios.
var coche2 = Tuple.Create("Opel", "Astra", 2005);
Técnicamente puedes crear una tupla dentro de otra, pero personalmente nunca he necesitado de hacerlo, y tengo mis dudas de que sea una buena idea, ya que empeorará la legibilidad del código.
1.2 - Acceder a los elementos de una tupla
Para acceder a cada uno de los elementos de la tupla lo hacemos a través de Item<ElementNumber>
.
Por ejemplo, en nuestro ejemplo tenemos tres propiedades con lo que accedemos con:
coche.Item1;
coche.Item2;
coche.Item3;
Lo cual nos permite hacer algo como lo siguiente:
Tuple<string, string, int> coche
= new Tuple<string, string, int>("Audi", "A3", 2008);
var coche2 = Tuple.Create("Opel", "Astra", 2005);
Console.WriteLine($"El primer coche es un {coche.Item1} {coche.Item2} del año {coche.Item3}");
Console.WriteLine($"El segundo coche es un {coche2.Item1} {coche2.Item2} del año {coche2.Item3}");
1.3 - Pasar Tuplas como parámetro
Un uso que le podemos dar es para pasar múltiples elementos a un método en un solo parámetro.
void ImprimirMensaje(Tuple<string, string, int> coche){
Console.WriteLine($"El coche es un {coche.Item1} {coche.Item2} del año {coche.Item3}");
}
1.4 - Devolver Tuplas de un método
El uso más común de la tupla es devolver múltiples valores de un método, y nos permite hacerlo de una forma muy sencilla y clara, únicamente indicamos Tupla<T>
como tipo de retorno y funciona sin problemas:
Tuple<string, string, int> CalcularCoche3()
{
return Tuple.Create("Ford", "Fiesta", 1995);
}
2 - Qué es ValueTuple?
Microsoft, después de presentar la Tupla<T>
se dio cuenta de que esta bien, pero había espacio para mejorar, así que en C#7 introdujo la estructura ValueTuple
, el cual es una representación por valor de la tupla.
2.1 - Inicializar ValueTuple en C#
Para inicializar objeto ValueTuple
es muy sencillo, únicamente debemos indicar los valores entre paréntesis ()
:
(string, string, int) moto1 = ("Derbi", "Variant", 1980);
Como vemos es muy similar a la Tupla
, pero con mucha menos sintaxis.
2.2 - Acceder a los elementos de ValueTuple
Para acceder a los elementos, realizamos la misma acción que en la tupla, utilizando Item<ElementNumber>
.
Console.WriteLine($"la moto es una {moto1.Item1} {moto1.Item2} del año {moto1.Item3}");
Pero no es la única opción, ya que cuando utilizamos ValueTuple
podemos poner un nombre o alias a las variables. Lo cual es muy importante ya que así nuestro código será mucho más fácil de entender.
(string marca, string modelo, int year) moto2 = ("Bultaco", "Lobito", 1998);
Console.WriteLine($"la moto es una {moto2.marca} {moto2.modelo} del año {moto2.year}");
Como podemos observar en vez de utilizar Item1, Item2, e Item3
hemos utilizado el alias que hemos indicado.
2.3 - ValueTuple como tipo de retorno
Igual que en las tuplas, el mayor uso que le vamos a dar al tipo ValueTuple va a ser como tipo de retorno, o cuando lo pasamos por parámetro a un método.
Como podemos observar es muy similar a lo visto anteriormente:
(string, string, int) CalcularMoto3(){
return ("Honda", "CBR", 2005);
}
void ImprimirMensajeMoto((string marca, string modelo, int year) moto)
{
Console.WriteLine($"la moto es una {moto.marca} {moto.modelo} del año {moto.year}");
}
2.4 - Deconstruir un objeto ValueTuple
Alternativamente podemos recibir múltiples valores de un ValueTuple
de forma individual haciendo uso del deconstructor
.
¿Qué quiere decir esto? Que podemos asignar un ValueTuple
directamente a múltiples variables individuales:
(string marcaMoto3, string modeloMoto3, int yearMoto3) = CalcularMoto3();
Console.WriteLine($"la moto es una {marcaMoto3} {modeloMoto3} del año {yearMoto3}");
Como puedes observar estamos haciendo uso de la variable marcaMoto3
y no de una propiedad dentro de un objeto.
- Nota: si no queremos hacer uso de una de las propiedades, siempre podemos utilizar
_
para descartarla.
Conclusión
- En este post hemos visto que son las Tuplas y ValueTuple en C# y cómo trabajar con ellas.
- Es recomendable el uso de tuplas cuando queremos devolver múltiples valores de un método, ya que así nos evitamos tener que poner
ref
uout
. - Además, podemos pasar múltiples elementos en un solo parámetro.
- No hay que olvidarse de que también tenemos limitaciones, como que solo podemos contener 8 elementos