Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Projekce odkazuje na operaci transformace objektu na nový formulář, který se často skládá pouze z těchto vlastností následně použitých. Pomocí projekce můžete vytvořit nový typ vytvořený z každého objektu. Vlastnost můžete projektovat a provádět s ní matematickou funkci. Můžete také projektovat původní objekt beze změny.
Důležité
Tyto ukázky používají zdroj dat System.Collections.Generic.IEnumerable<T>. Zdroje dat, které jsou založené na System.Linq.IQueryProvider, používají zdroje dat System.Linq.IQueryable<T> a stromy výrazů . Stromy výrazů mají omezení povolené syntaxe jazyka C#. Každý zdroj dat IQueryProvider, například EF Core, může navíc uplatňovat další omezení. Projděte si dokumentaci ke zdroji dat.
Standardní metody operátoru dotazu, které provádějí projekci, jsou uvedeny v následující části.
Metody
| Názvy metod | Popis | Syntaxe výrazu dotazu jazyka C# | Více informací |
|---|---|---|---|
| Vyberte | Hodnoty projektů založené na transformační funkci | select |
Enumerable.Select Queryable.Select |
| SelectMany | Promítá sekvence hodnot založené na transformační funkci a následně je zploští do jedné sekvence. | Použití více from klauzulí |
Enumerable.SelectMany Queryable.SelectMany |
| ZIP | Vytvoří sekvenci n-tic s prvky ze 2 nebo 3 zadaných sekvencí. | Nelze použít. | Enumerable.Zip Queryable.Zip |
Select
Následující příklad pomocí select klauzule projektuje první písmeno z každého řetězce v seznamu řetězců.
Poznámka:
Běžné zdroje dat pro tuto oblast najdete v článku Přehled standardních operátorů dotazů .
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
*/
Ekvivalentní dotaz pomocí syntaxe metody se zobrazí v následujícím kódu:
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
Následující příklad používá více from klauzulí k projektování každého slova z každého řetězce v seznamu řetězců.
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
*/
Ekvivalentní dotaz pomocí syntaxe metody se zobrazí v následujícím kódu:
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
*/
Metoda SelectMany může také vytvořit kombinaci shody každé položky v první sekvenci s každou položkou ve druhé sekvenci:
var query = from number in numbers
from letter in letters
select (number, letter);
foreach (var item in query)
{
Console.WriteLine(item);
}
Ekvivalentní dotaz pomocí syntaxe metody se zobrazí v následujícím kódu:
var method = numbers
.SelectMany(number => letters,
(number, letter) => (number, letter));
foreach (var item in method)
{
Console.WriteLine(item);
}
Zip
Operátor projekce má několik přetížení Zip .
Zip Všechny metody pracují na sekvencích dvou nebo více možná heterogenních typů. První dvě přetížení vrací řazené kolekce členů s odpovídajícím pozičním typem z daných sekvencí.
Zvažte následující kolekce:
// 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'];
Pokud chcete tyto sekvence promítnout dohromady, použijte Enumerable.Zip<TFirst,TSecond>(IEnumerable<TFirst>, IEnumerable<TSecond>) operátor:
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'
Důležité
Výsledná posloupnost z zipové operace není nikdy delší než nejkratší sekvence.
numbers a letters kolekce se liší délkou a výsledná sekvence vynechá poslední prvek z numbers kolekce, protože nemá s čím být spárován.
Druhé přetížení přijímá third sekvenci. Pojďme vytvořit další kolekci, konkrétně emoji:
// A string array with 8 elements.
IEnumerable<string> emoji = [ "🤓", "🔥", "🎉", "👀", "⭐", "💜", "✔", "💯"];
Pokud chcete tyto sekvence promítnout dohromady, použijte Enumerable.Zip<TFirst,TSecond,TThird>(IEnumerable<TFirst>, IEnumerable<TSecond>, IEnumerable<TThird>) operátor:
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: 💜
Podobně jako předchozí přetížení, metoda Zip projektuje n-tici, ale tentokrát se třemi prvky.
Třetí přetížení přijímá Func<TFirst, TSecond, TResult> argument, který funguje jako selektor výsledků. Můžete promítnout novou výslednou sekvenci ze sekvencí, které jsou slučovány.
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)
Při předchozím Zip přetížení se zadaná funkce použije na odpovídající prvky number a letter, a vytvoří sekvenci string výsledků.
Select proti SelectMany
Práce obou Select a SelectMany je vytvořit výslednou hodnotu (nebo hodnoty) ze zdrojových hodnot.
Select vytvoří jednu výslednou hodnotu pro každou zdrojnou hodnotu. Celkový výsledek je tedy kolekce, která má stejný počet prvků jako zdrojová kolekce. Naproti tomu SelectMany vytvoří jeden komplexní výsledek, který obsahuje zřetězené dílčí kolekce z každé zdrojové hodnoty. Transformační funkce, která je předána jako argument, SelectMany musí vrátit výčet hodnot pro každou zdrojovou hodnotu.
SelectMany zřetězí tyto výčtové sekvence a vytvoří jednu velkou sekvenci.
Následující dva ilustrace ukazují koncepční rozdíl mezi akcemi těchto dvou metod. V každém případě předpokládejme, že funkce selektoru (transformace) vybere pole květin z každé zdrojové hodnoty.
Tento obrázek znázorňuje, jak Select vrátí kolekci, která má stejný počet prvků jako zdrojová kolekce.
Tento obrázek znázorňuje, jak SelectMany zřetězí průběžnou sekvenci polí do jedné konečné výsledné hodnoty, která obsahuje každou hodnotu z každého zprostředkujícího pole.
Příklad kódu
Následující příklad porovnává chování Select a SelectMany. Kód vytvoří "kytice" květin tím, že vezme položky z každého seznamu názvů květin ve zdrojové kolekci. V následujícím příkladu je "jednoduchá hodnota", kterou transformační funkce Select<TSource,TResult>(IEnumerable<TSource>, Func<TSource,TResult>) používá, kolekcí hodnot. Tento příklad vyžaduje dodatečnou foreach smyčku, aby se každý řetězec v jednotlivých dílčích sekvencích vyčíslil.
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);
}
}