Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
A projeção refere-se à operação de transformação de um objeto em um novo formulário que geralmente consiste apenas nessas propriedades usadas posteriormente. Usando a projeção, você pode construir um novo tipo criado a partir de cada objeto. Você pode projetar uma propriedade e executar uma função matemática nela. Você também pode projetar o objeto original sem alterá-lo.
Importante
Esses exemplos usam uma fonte de dados System.Collections.Generic.IEnumerable<T>. Fontes de dados baseadas em System.Linq.IQueryProvider usam as fontes de dados System.Linq.IQueryable<T> e as árvores de expressão. As árvores de expressão possuem limitações na sintaxe C# permitida. Além disso, todas as fontes de dados IQueryProvider
, como EF Core, podem impor mais restrições. Verifique a documentação da fonte de dados.
Os métodos de operador de consulta padrão que executam a projeção são listados na seção a seguir.
Métodos
Nomes de método | Descrição | Sintaxe da expressão de consulta C# | Mais informações |
---|---|---|---|
Selecionar | Projeta valores baseados em uma função de transformação. | select |
Enumerable.Select Queryable.Select |
SelectMany | Projeta sequências de valores que são baseados em uma função de transformação e, em seguida, os nivela em uma sequência. | Use várias cláusulas from |
Enumerable.SelectMany Queryable.SelectMany |
Nada | Produz uma sequência de tuplas com elementos provenientes de 2 ou 3 sequências especificadas. | Não aplicável. | Enumerable.Zip Queryable.Zip |
Select
O exemplo a seguir usa a select
cláusula para projetar a primeira letra de cada cadeia de caracteres em uma lista de cadeias de caracteres.
List<string> words = ["an", "apple", "a", "day"];
var query = from word in words
select word.Substring(0, 1);
foreach (string s in query)
{
Console.WriteLine(s);
}
/* This code produces the following output:
a
a
a
d
*/
A consulta equivalente usando a sintaxe do método é mostrada no código a seguir:
List<string> words = ["an", "apple", "a", "day"];
var query = words.Select(word => word.Substring(0, 1));
foreach (string s in query)
{
Console.WriteLine(s);
}
/* This code produces the following output:
a
a
a
d
*/
SelectMany
O exemplo a seguir usa várias cláusulas from
para projetar cada palavra de cada cadeia de caracteres em uma lista de cadeias de caracteres.
List<string> phrases = ["an apple a day", "the quick brown fox"];
var query = from phrase in phrases
from word in phrase.Split(' ')
select word;
foreach (string s in query)
{
Console.WriteLine(s);
}
/* This code produces the following output:
an
apple
a
day
the
quick
brown
fox
*/
A consulta equivalente usando a sintaxe do método é mostrada no código a seguir:
List<string> phrases = ["an apple a day", "the quick brown fox"];
var query = phrases.SelectMany(phrase => phrase.Split(' '));
foreach (string s in query)
{
Console.WriteLine(s);
}
/* This code produces the following output:
an
apple
a
day
the
quick
brown
fox
*/
O método SelectMany
também pode formar a combinação de correspondência de cada item na primeira sequência com cada item na segunda sequência:
var query = from number in numbers
from letter in letters
select (number, letter);
foreach (var item in query)
{
Console.WriteLine(item);
}
A consulta equivalente usando a sintaxe do método é mostrada no código a seguir:
var method = numbers
.SelectMany(number => letters,
(number, letter) => (number, letter));
foreach (var item in method)
{
Console.WriteLine(item);
}
Zip
Há várias sobrecargas para o operador de projeção Zip
. Todos os Zip
métodos funcionam em sequências de dois ou mais tipos possivelmente heterogêneos. As duas primeiras sobrecargas retornam tuplas com o tipo posicional correspondente das sequências fornecidas.
Considere as seguintes coleções:
// An int array with 7 elements.
IEnumerable<int> numbers = [1, 2, 3, 4, 5, 6, 7];
// A char array with 6 elements.
IEnumerable<char> letters = ['A', 'B', 'C', 'D', 'E', 'F'];
Para projetar essas sequências em conjunto, use o Enumerable.Zip<TFirst,TSecond>(IEnumerable<TFirst>, IEnumerable<TSecond>) operador:
foreach ((int number, char letter) in numbers.Zip(letters))
{
Console.WriteLine($"Number: {number} zipped with letter: '{letter}'");
}
// This code produces the following output:
// Number: 1 zipped with letter: 'A'
// Number: 2 zipped with letter: 'B'
// Number: 3 zipped with letter: 'C'
// Number: 4 zipped with letter: 'D'
// Number: 5 zipped with letter: 'E'
// Number: 6 zipped with letter: 'F'
Importante
A sequência resultante de uma operação zip nunca tem mais comprimento do que a sequência mais curta. As coleções numbers
e letters
diferem em comprimento, e a sequência resultante omite o último elemento da coleção numbers
, pois não tem nada com o qual combinar.
A segunda sobrecarga aceita uma sequência third
. Vamos criar outra coleção, ou seja emoji
:
// A string array with 8 elements.
IEnumerable<string> emoji = [ "🤓", "🔥", "🎉", "👀", "⭐", "💜", "✔", "💯"];
Para projetar essas sequências em conjunto, use o Enumerable.Zip<TFirst,TSecond,TThird>(IEnumerable<TFirst>, IEnumerable<TSecond>, IEnumerable<TThird>) operador:
foreach ((int number, char letter, string em) in numbers.Zip(letters, emoji))
{
Console.WriteLine(
$"Number: {number} is zipped with letter: '{letter}' and emoji: {em}");
}
// This code produces the following output:
// Number: 1 is zipped with letter: 'A' and emoji: 🤓
// Number: 2 is zipped with letter: 'B' and emoji: 🔥
// Number: 3 is zipped with letter: 'C' and emoji: 🎉
// Number: 4 is zipped with letter: 'D' and emoji: 👀
// Number: 5 is zipped with letter: 'E' and emoji: ⭐
// Number: 6 is zipped with letter: 'F' and emoji: 💜
Assim como a sobrecarga anterior, o Zip
método projeta uma tupla, mas desta vez com três elementos.
A terceira sobrecarga aceita um Func<TFirst, TSecond, TResult>
argumento que atua como um seletor de resultados. Você pode projetar uma nova sequência resultante das sequências que estão sendo compactadas.
foreach (string result in
numbers.Zip(letters, (number, letter) => $"{number} = {letter} ({(int)letter})"))
{
Console.WriteLine(result);
}
// This code produces the following output:
// 1 = A (65)
// 2 = B (66)
// 3 = C (67)
// 4 = D (68)
// 5 = E (69)
// 6 = F (70)
Com a sobrecarga anterior Zip
, a função especificada é aplicada aos elementos correspondentes number
e letter
, produzindo uma sequência dos string
resultados.
Select
contra SelectMany
O trabalho de ambos Select
e SelectMany
é produzir um valor de resultado (ou valores) de valores de origem.
Select
produz um valor de resultado para cada valor de origem. O resultado geral é, portanto, uma coleção que tem o mesmo número de elementos que a coleção de origem. Por outro lado, SelectMany
produz um único resultado geral que contém subcolleções concatenadas de cada valor de origem. A função de transformação que é passada como um argumento para SelectMany
deve retornar uma sequência enumerável de valores para cada valor de origem.
SelectMany
concatena essas sequências enumeráveis para criar uma sequência grande.
As duas ilustrações a seguir mostram a diferença conceitual entre as ações desses dois métodos. Em cada caso, presuma que a função de seletor (transformação) seleciona a matriz de flores de cada valor de origem.
Esta ilustração mostra como Select
retorna uma coleção que tem o mesmo número de elementos que a coleção de origem.
Esta ilustração descreve como SelectMany
concatena a sequência intermediária de matrizes em um valor de resultado final que contém cada valor de cada matriz intermediária.
Exemplo de código
O exemplo a seguir compara o comportamento de Select
e SelectMany
. O código cria um "buquê" de flores tirando os itens de cada lista de nomes de flores na coleção de origem. No exemplo a seguir, o "valor único" usado pela função Select<TSource,TResult>(IEnumerable<TSource>, Func<TSource,TResult>) de transformação é uma coleção de valores. Este exemplo requer o loop extra foreach
para enumerar cada cadeia de caracteres em cada subsequência.
class Bouquet
{
public required List<string> Flowers { get; init; }
}
static void SelectVsSelectMany()
{
List<Bouquet> bouquets =
[
new Bouquet { Flowers = ["sunflower", "daisy", "daffodil", "larkspur"] },
new Bouquet { Flowers = ["tulip", "rose", "orchid"] },
new Bouquet { Flowers = ["gladiolis", "lily", "snapdragon", "aster", "protea"] },
new Bouquet { Flowers = ["larkspur", "lilac", "iris", "dahlia"] }
];
IEnumerable<List<string>> query1 = bouquets.Select(bq => bq.Flowers);
IEnumerable<string> query2 = bouquets.SelectMany(bq => bq.Flowers);
Console.WriteLine("Results by using Select():");
// Note the extra foreach loop here.
foreach (IEnumerable<string> collection in query1)
{
foreach (string item in collection)
{
Console.WriteLine(item);
}
}
Console.WriteLine("\nResults by using SelectMany():");
foreach (string item in query2)
{
Console.WriteLine(item);
}
}