1. Nomeando tuplas: contexto pra deconstrução
Na aula passada a gente já viu os elementos nomeados das tuplas, que deixam o código bem mais fácil de ler, porque você acessa os valores por nomes que fazem sentido, e não por Item1, Item2 sem graça. Por exemplo, person.Name. Dar nome pros elementos da tupla é super importante, principalmente quando ela é usada como retorno de métodos, parâmetros ou propriedades. Nomear é o segredo pra deconstrução ficar fácil, e é isso que vamos ver agora nessa aula.
Só lembrando: dá pra colocar nomes na hora de inicializar a tupla pelo literal, e também na assinatura do retorno do método, propriedade ou campo.
Exemplo com método: Elementos nomeados na tupla de retorno do método
public static (int Idade, string Nome) GetPetInfo()
{
return (Idade: 5, Nome: "Barsik");
}
// Usando:
var info = GetPetInfo();
Console.WriteLine($"{info.Nome} — {info.Idade} anos");
Exemplo com campo/propriedade: Elementos nomeados na tupla em campo/propriedade
public (int Largura, int Altura) TamanhoImagem = (1024, 768);
Lembra aí: se você não colocar nomes, os elementos ainda vão estar disponíveis como Item1, Item2 e por aí vai. Isso pode deixar o código mais difícil de entender, principalmente quando a tupla é usada depois. Por isso, sempre que der, coloca nomes que façam sentido pros elementos, se não ficar óbvio pelo contexto.
2. Deconstrução de tuplas
O que é deconstrução?
Deconstrução é o processo de "desmontar" a tupla em variáveis separadas, pra ficar mais fácil de trabalhar com elas. Tipo, de uma tupla (Idade: 5, Nome: "Barsik") você tira duas variáveis: idade e nome.
Analogia: Imagina que a tupla é uma caixa com divisórias nomeadas. Deconstruir é como já tirar tudo da caixa e colocar cada coisa no seu lugar na mesa.
Sintaxe da deconstrução
var pet = (Idade: 5, Nome: "Barsik");
var (idade, nome) = pet;
Console.WriteLine($"{nome} — {idade} anos");
Agora temos duas variáveis: idade e nome. Elas pegaram os valores da tupla. Os nomes à esquerda (idade, nome) não precisam ser iguais aos nomes da tupla, são só novas variáveis locais.
Deconstruindo retorno de função
Tuplas são muito usadas pra retornar vários valores de uma função. Aí a deconstrução brilha:
public static (double minimo, double maximo) GetMinMax(int[] dados)
{
int minimo = dados.Min();
int maximo = dados.Max();
return (minimo, maximo);
}
var numeros = new[] { 1, 2, 3, 4, 5 };
var (valorMinimo, valorMaximo) = GetMinMax(numeros);
Console.WriteLine($"Mínimo: {valorMinimo}, máximo: {valorMaximo}");
Repara que na deconstrução você pode dar o nome que quiser pras variáveis, do jeito que ficar melhor no contexto.
Deconstrução com var
var (a, b) = (10, 20); // int a = 10, b = 20
Deconstrução e discard _
Às vezes você não precisa de todos os elementos da tupla. Dá pra ignorar eles usando _ (discard). Discard (_) na tupla é só um jeito de falar "sei que tem outro elemento aqui, mas não quero ele, não cria variável pra isso".
Assim, você deconstrói a tupla mas deixa um "buraco" onde não precisa do valor. Bem prático e sem complicação!
var pet = (Idade: 5, Nome: "Barsik", EstaFeliz: true);
var (idade, _, estaFeliz) = pet; // só idade e estaFeliz, nome foi ignorado
Curiosidade: discard é muito usado pra não poluir o escopo com variáveis que você não vai usar.
Deconstrução em loop foreach
No C# dá pra percorrer um array de tuplas deconstruindo direto no foreach:
var pets = new (string Nome, int Idade)[]
{
("Barsik", 5),
("Musya", 3),
("Dzhonni", 7)
};
foreach (var (nome, idade) in pets)
{
Console.WriteLine($"{nome} — {idade} anos");
}
3. Como funcionam os nomes dos elementos e tipagem
Comportamento dos elementos nomeados
Os nomes dos elementos da tupla são só "açúcar sintático", ou seja, pra facilitar pra gente. Na hora de compilar, os nomes viram campos internos Item1, Item2 e tal, mas a IDE e o compilador guardam os nomes pra você poder usar.
Impacto na compatibilidade de tipos e conversão
Duas tuplas com a mesma quantidade de elementos e tipos, mas nomes diferentes, são consideradas do mesmo tipo pelo compilador. Os nomes não fazem parte da definição do tipo:
var t1 = (X: 42, Y: 13);
var t2 = (A: 42, B: 13);
t1 = t2; // OK
Console.WriteLine(t1.X); // 42
Mas quando você trabalha com expressões e dicas do IntelliSense, os nomes usados vão ser os da esquerda (pra onde você está atribuindo), não os da direita.
Nomeando elementos de forma implícita e explícita
A gente já viu isso, mas só pra reforçar: dá pra criar tuplas com alguns elementos nomeados, outros não, ou nem nomear nada — aí fica só Item1 e por aí vai.
var ponto = (X: 10, 20); // X e Item2
Console.WriteLine(ponto.X); // 10
Console.WriteLine(ponto.Item2); // 20
Dica: sempre nomeie os elementos se a tupla tiver mais de um ou dois elementos, ou se o significado não ficar claro pelo contexto.
4. Erros comuns e pegadinhas com nomes e deconstrução
Erro nº1: “nomes que ficam” ao atribuir tuplas diferentes
Se você declarou uma tupla com certos nomes, e depois atribuiu outra tupla sem nomes (ou com nomes diferentes), no IntelliSense ainda vão aparecer os nomes originais. Exemplo:
var original = (X: 1, Y: 2);
var alias = original; // alias.X == 1, alias.Y == 2
original = (10, 20); // tupla sem nomes
Console.WriteLine(alias.X); // ainda funciona, mas alias ainda guarda os nomes antigos
Erro nº2: nomes duplicados nos elementos.
Não dá pra dar o mesmo nome pra dois elementos — o compilador vai reclamar com “Duplicate tuple element name”:
var tuplaErrada = (A: 1, A: 2); // Erro CS8122: Duplicate tuple element name 'A'
Erro nº3: deconstrução errada pelo número de elementos.
Na deconstrução, o número de variáveis tem que bater certinho com o tamanho da tupla. Se não, dá erro:
var pet = (Idade: 5, Nome: "Barsik");
var (idade, nome, humor) = pet; // Erro CS8124: Tuple must contain exactly 3 elements
Erro nº4: uso errado do discard _
Ignorar elementos com _ funciona pra cada posição separada, não “junta” os buracos. Se tentar pular dois elementos com um só _, vai dar erro:
var dados = (1, 2, 3);
var (_, x, _) = dados; // Certo: pulou o primeiro e o terceiro elementos
var (_, _) = dados; // Erro CS8124: Tuple must contain exactly 2 elements
GO TO FULL VERSION