Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Sugestão
Novo no desenvolvimento de software? Começa pelos tutoriais para começar . Vais encontrar tuplas quando precisares de devolver múltiplos valores de um método ou de agrupar valores sem definir um tipo nomeado.
Experiente noutra língua? Tuplas no C# são tipos de valores semelhantes às tuplas em Python ou Swift, mas com a opção de conter elementos nomeados e suporte total para desconstrução. Verifique as secções de desconstrução e de igualdade para padrões específicos de C#.
Uma tupla agrupa múltiplos valores numa única estrutura leve sem que seja necessário definir um tipo nomeado. Tuplas são tipos de valor que podes declarar em linha, retornar de métodos e decompor em variáveis individuais. Use tuplas quando precisar de um agrupamento rápido e temporário de valores relacionados. Por exemplo, quando devolve múltiplos resultados de um método ou armazena um par de coordenadas.
O exemplo seguinte cria uma tuplo com elementos nomeados e acede a cada elemento pelo nome:
var location = (Latitude: 47.6062, Longitude: -122.3321);
Console.WriteLine($"Location: {location.Latitude}, {location.Longitude}");
// Output: Location: 47.6062, -122.3321
As tuplas funcionam bem para agrupamentos de curta duração onde definir uma classe, struct ou registo acrescentaria cerimónia desnecessária. Para conceitos ou tipos de domínio de longa duração com comportamento, prefira registos, classes ou structs. Para uma comparação de quando usar cada um, consulte Escolher que tipo usar.
Declarar e inicializar tuplas
Declare uma tupla listando os tipos de elementos entre parênteses. Pode, opcionalmente, nomear cada elemento para tornar o código mais legível:
// Tuple with named elements
(string Name, int Age) person = ("Alice", 30);
Console.WriteLine($"{person.Name} is {person.Age} years old");
// Tuple with default element names (Item1, Item2)
(string, int) unnamed = ("Bob", 25);
Console.WriteLine($"{unnamed.Item1} is {unnamed.Item2} years old");
// Tuple declared with var and inline names
var city = (Name: "Seattle", Population: 749_256);
Console.WriteLine($"{city.Name}: population {city.Population}");
Quando não fornece nomes, os elementos usam nomes padrão Item1, Item2 e assim sucessivamente. Elementos nomeados tornam o seu código auto-documentado sem exigir uma definição de tipo separada.
Nomes de elementos inferidos
O compilador infere os nomes dos elementos a partir dos nomes das variáveis ou dos nomes das propriedades que usa para inicializar a tupla. Esta funcionalidade evita redundância quando os nomes coincidem:
var name = "Carol";
var age = 28;
// The compiler infers element names from the variable names
var person = (name, age);
Console.WriteLine($"{person.name} is {person.age}");
// Output: Carol is 28
Nomes inferidos mantêm o seu código conciso. Se precisares de um nome de elemento diferente, especifica-o explicitamente.
Devolver múltiplos valores de um método
Uma das utilizações mais comuns de tuplas é retornar múltiplos valores de um método. Em vez de definir uma classe ou usar out parâmetros, devolve-se uma tupla com elementos nomeados:
static (double Minimum, double Maximum, double Average) ComputeStats(List<double> values)
{
var min = values.Min();
var max = values.Max();
var avg = values.Average();
return (min, max, avg);
}
Elementos de tuplas nomeados tornam os valores de retorno legíveis quer no local da chamada, quer na assinatura do método. O chamador pode aceder a cada valor pelo nome sem precisar de se lembrar da ordem posicional.
Desconstruir tuplas
A desconstrução desempacota os elementos de uma tupla em variáveis separadas numa única afirmação. Pode desconstruir tuplas de várias formas:
var point = (X: 3, Y: 7);
// Deconstruct with var (infer all types)
var (x, y) = point;
Console.WriteLine($"x={x}, y={y}");
// Deconstruct with explicit types
(int px, int py) = point;
Console.WriteLine($"px={px}, py={py}");
// Deconstruct into existing variables
int a, b;
(a, b) = point;
Console.WriteLine($"a={a}, b={b}");
// Deconstruct a method return value directly
List<double> data = [10.0, 20.0, 30.0];
var (min, max, avg) = ComputeStats(data);
Console.WriteLine($"Min: {min}, Max: {max}, Avg: {avg}");
A desconstrução é especialmente útil quando recebe uma tupla de uma chamada de método e precisa de trabalhar imediatamente com os seus valores individuais.
Pode desconstruir tuplas diretamente em foreach loops, o que torna a iteração sobre coleções de valores agrupados mais concisa:
List<(string Name, int Score)> results =
[
("Alice", 92),
("Bob", 87),
("Carol", 95)
];
foreach (var (name, score) in results)
{
Console.WriteLine($"{name}: {score}");
}
Quando não precisares de todos os elementos, usa um descarte (_) em vez de cada valor que queres ignorar. Use um _ separado para cada posição descartada:
List<double> values = [5.0, 10.0, 15.0];
var (_, max, _) = ComputeStats(values);
Console.WriteLine($"Only need the max: {max}");
// Output: Only need the max: 15
Para saber mais sobre o uso de descartes em diferentes contextos, veja Descartes.
Igualdade tupla
Pode comparar tuplas usando == e !=. Estes operadores comparam cada elemento por ordem, de modo que duas tuplas são iguais quando todos os seus elementos correspondentes são iguais:
var order1 = (Product: "Widget", Quantity: 5);
var order2 = (Product: "Widget", Quantity: 5);
var order3 = (Product: "Gadget", Quantity: 3);
Console.WriteLine(order1 == order2); // True
Console.WriteLine(order1 == order3); // False
// Element names don't affect equality—only values matter
var named = (X: 1, Y: 2);
var different = (A: 1, B: 2);
Console.WriteLine(named == different); // True
A igualdade de tuplas usa o == operador definido em cada tipo de elemento, o que significa que a comparação funciona corretamente para cadeias, números e outros tipos que definem ==. Os nomes dos elementos não afetam a igualdade — apenas os valores e posições importam.
Mutação não destrutiva com with
A with expressão cria uma cópia de uma tupla com um ou mais elementos alterados, deixando o original inalterado.
var original = (Name: "Widget", Price: 19.99m, InStock: true);
var discounted = original with { Price = 14.99m };
Console.WriteLine($"Original: {original.Name} at {original.Price:C}");
Console.WriteLine($"Discounted: {discounted.Name} at {discounted.Price:C}");
// Output:
// Original: Widget at $19.99
// Discounted: Widget at $14.99
Este padrão é útil quando se quer uma variação de uma tupla existente sem modificar o original. A with expressão funciona da mesma forma nas tuplas que nos discos.
Tuplas em dicionários e consultas
As tuplas são valores convenientes para o dicionário quando é necessário associar uma chave a múltiplas peças de dados:
var sizeChart = new Dictionary<string, (int Min, int Max)>
{
["Small"] = (0, 50),
["Medium"] = (51, 100),
["Large"] = (101, 200)
};
if (sizeChart.TryGetValue("Medium", out var range))
{
Console.WriteLine($"Medium: {range.Min}–{range.Max}");
}
// Output: Medium: 51–100
As tuplas também funcionam como chaves de dicionário, dando-lhe uma chave composta sem definir um tipo personalizado. Como as tuplas implementam igualdade estrutural, as consultas correspondem nos valores combinados de todos os elementos:
var grid = new Dictionary<(int Row, int Column), string>
{
[(0, 0)] = "Origin",
[(1, 3)] = "Sensor A",
[(2, 5)] = "Sensor B"
};
var target = (Row: 1, Column: 3);
if (grid.TryGetValue(target, out var label))
{
Console.WriteLine($"({target.Row}, {target.Column}): {label}");
}
// Output: (1, 3): Sensor A
Este padrão evita a necessidade de uma classe separada para consultas simples de múltiplas chaves ou mapeamentos chave-para-múltiplos valores.
Tuplas vs. tipos anónimos
As tuplas são a escolha preferida quando precisas de uma estrutura de dados leve e sem nome. Os tipos anónimos continuam disponíveis para cenários de árvore de expressões e para código que requer tipos de referência, mas as tuplas oferecem melhor desempenho, suporte para desconstrução e sintaxe mais flexível. Para mais informações sobre tipos anónimos, consulte Escolher entre tipos anónimos e tuplas.
Consulte também
- Tipos de tuplas (referência C#) para detalhes completos da sintaxe
-
Desconstrução de tuplas e outros tipos para métodos definidos
Deconstructpelo utilizador - Devoluções
- Registos