CodeGym /Cursos /C# SELF /Nomeando elementos e deconstruindo tuplas

Nomeando elementos e deconstruindo tuplas

C# SELF
Nível 11 , Lição 2
Disponível

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");
Deconstruindo a tupla em variáveis

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}");
Deconstruindo o retorno da função

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
Deconstrução com discard _

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");
}
Deconstruindo tuplas no foreach

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
Compatibilidade de tuplas com nomes diferentes nos elementos

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
Tupla parcialmente nomeada

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

Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION