Introducción a Tuplas en C# en 10 Minutos o Menos
[[academy-video-youtube({"vid": "QC6hpl2iU0c", "start_time": "0", "title": "Intro to Tuples in C# In 10 Minutes or Less", "creator": "Tim Corey", "length": "9m 49s"})]]
Los métodos en C# están diseñados alrededor de un único valor de retorno, lo cual funciona hasta que te encuentras con un caso donde una sola devolución no es suficiente. La validación de direcciones es el ejemplo clásico: necesitas saber si la entrada es válida, y si lo es, quieres que te devuelva la forma canónica corregida. Envolver ese par en una clase nueva se siente pesado para un método, y los parámetros de salida mezclan la entrada y salida de una manera que envejece mal. Se agregaron las tuplas al lenguaje precisamente para que esta situación tenga una respuesta más limpia.
En su video "Intro to Tuples in C# In 10 Minutes or Less", Tim Corey explora las tuplas construyendo un pequeño método de validación de dirección que necesita devolver tanto una cadena formateada como una bandera de validez. En el camino cubre la sintaxis para devolver una tupla, por qué asignar nombres a los miembros importa, cómo descomponer el resultado en variables separadas en el lugar de la llamada, y cómo saltarse las partes que no te importan con el carácter de descarte. Los lectores que todavía recurren a clases de resultados de un solo uso o parámetros out encontrarán un patrón más ligero aquí.
El Problema: Devolver Más de Un Valor
[0:18 - 2:50] Tim comienza con un método ValidateAddress que acepta una cadena de dirección postal. El comportamiento que desea es directo: si la entrada coincide con "123 Sesame St", devuelve el "123 Sesame Street" debidamente formateado; de lo contrario, señala que la dirección no es válida. Necesitan volver dos piezas de información de una sola llamada, la cadena corregida y la bandera de éxito.
Las opciones pre-tupla son incómodas. Crear una clase ValidateAddressResult funciona, pero deja un tipo de un solo propósito en el proyecto que ningún otro código instanciará. Usar un parámetro de salida para enviar la dirección formateada a través de la lista de parámetros también funciona, pero mezcla entrada y salida en la firma del método y hace que el lugar de la llamada sea más difícil de leer. Las tuplas se introdujeron para manejar este caso sin pagar ninguno de esos costos.
Devolver una Tupla No Nombrada
[2:50 - 4:01] La sintaxis mínima para un tipo de retorno de tupla envuelve los dos tipos entre paréntesis:
public (string, bool) ValidateAddress(string address)
{
if (address == "123 Sesame St")
{
return ("123 Sesame Street", true);
}
return (address, false);
}public (string, bool) ValidateAddress(string address)
{
if (address == "123 Sesame St")
{
return ("123 Sesame Street", true);
}
return (address, false);
}El método ahora devuelve un par (string, bool). La desventaja aparece inmediatamente cuando algo intenta usarlo. Sin nombres asignados a los miembros, IntelliSense los expone como Item1 y Item2, lo cual no informa nada al siguiente lector sobre lo que representa cada valor. Tim señala esto como la razón por la que nunca envía tuplas sin nombre, aunque la sintaxis es la más corta. El costo de leer result.Item2 seis meses después es mayor que el costo de escribir un nombre una vez.
Nombrando los Miembros de la Tupla
[4:01 - 6:30] Asignar nombres a cada miembro de la tupla es un cambio de una sola línea en la declaración del tipo de retorno:
public (string Address, bool IsValid) ValidateAddress(string address)
{
if (address == "123 Sesame St")
{
return ("123 Sesame Street", true);
}
return (address, false);
}public (string Address, bool IsValid) ValidateAddress(string address)
{
if (address == "123 Sesame St")
{
return ("123 Sesame Street", true);
}
return (address, false);
}Ahora el lugar de la llamada se lee de manera natural:
var result = ValidateAddress("123 Sesame St");
if (result.IsValid)
{
Console.WriteLine($"Your validated address is {result.Address}");
}
else
{
Console.WriteLine("That is an invalid address");
}var result = ValidateAddress("123 Sesame St");
if (result.IsValid)
{
Console.WriteLine($"Your validated address is {result.Address}");
}
else
{
Console.WriteLine("That is an invalid address");
}Ejecutar el código con "123 Sesame St" imprime la forma canónica. Eliminar el primer 1 para producir "23 Sesame St" hace que IsValid regrese como falso y se imprima el mensaje de dirección inválida. El contrato del método ahora se documenta automáticamente en el lugar de la llamada sin que una tupla nombrada requiera un archivo de clase de soporte.
Una tupla puede llevar más de dos miembros. Tres, cuatro o cinco funcionan de la misma manera. Tim señala que una vez que una tupla crece más allá de tres o cuatro miembros, un registro o clase generalmente se convierte en la opción más clara, pero para dos o tres valores relacionados de un solo método, la tupla sigue siendo la opción más ligera.
Descomposición de la Tupla en Variables Separadas
[6:30 - 7:39] A veces, al llamante le gustaría mantener cada parte del resultado en su propia variable en lugar de acceder a un único result. C# lo admite directamente con la sintaxis de descomposición:
(string message, bool valid) = ValidateAddress("123 Sesame St");
if (valid)
{
Console.WriteLine($"Your validated address is {message}");
}(string message, bool valid) = ValidateAddress("123 Sesame St");
if (valid)
{
Console.WriteLine($"Your validated address is {message}");
}Los nombres de las variables en el lado izquierdo no tienen que coincidir con los nombres de los miembros de la tupla en el método. Aquí message reemplaza a Address y valid reemplaza a IsValid. Tim señala que esto es un deconstructor, no un destructor; las dos palabras suenan similares pero se refieren a conceptos completamente diferentes. El deconstructor divide la tupla en las variables locales que realmente quiere el que llama.
Omitiendo Valores con el Carácter de Descarte
[7:41 - 8:54] Cuando al llamante solo le importan un subconjunto de los valores devueltos, el carácter de descarte (_) elimina los que no necesita:
(string message, _) = ValidateAddress("123 Sesame St");
Console.WriteLine(message);(string message, _) = ValidateAddress("123 Sesame St");
Console.WriteLine(message);El guion bajo le dice al compilador "Estoy ignorando este valor a propósito". Esto es más expresivo que asignar el miembro no deseado a un nombre de variable de descarte como unused, porque un descarte comunica intención. Cualquiera que lea la línea sabe que ignorar IsValid es una elección deliberada para este punto de llamada, no un descuido.
Conclusión: Cuando las Tuplas Ganan su Lugar
[8:54 - 9:28] El caso de uso principal para las tuplas es devolver múltiples valores desde un método sin crear una clase que existe solo para ser devuelta una vez. Nombrar los miembros en la firma del método, descomponerlos en el lugar de la llamada y descartar los que el que llama no necesita son los tres patrones que hacen que las tuplas sean cómodas para vivir con ellas. Más allá de eso, las tuplas son útiles en proyecciones LINQ y cálculos intermedios donde un valor emparejado rápido es más legible que un tipo anónimo.
Conclusión
[9:28 - 9:49] Las tuplas le dan a C# una forma compacta de devolver más de un valor desde un método. La forma nombrada es la versión que vale la pena usar día a día, porque result.Address se lee mientras que result.Item1 no. La descomposición promueve las partes de nuevo a variables locales cuando el que llama prefiere esa forma, y el carácter de descarte permite que una sola llamada tome solo lo que necesita.
Consejo de Ejemplo: Cuando comienzas a descomponer la misma forma de tupla en tres o más lugares, esa es la señal para pasar a un registro en su lugar. Las tuplas brillan cuando la forma es local a un método; el momento en que la forma se convierte en parte de tu dominio, un tipo nombrado se paga por sí mismo.
Mira el video completo en su canal de YouTube y obtén más información sobre cómo escribir C# moderno y expresivo en la serie de Entrenamiento de 10 Minutos.

