Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Projektion bezieht sich auf den Vorgang der Transformation eines Objekts in eine neue Form, die häufig nur aus diesen eigenschaften besteht, die anschließend verwendet werden. Mithilfe der Projektion können Sie einen neuen Typ erstellen, der aus jedem Objekt erstellt wird. Sie können eine Eigenschaft projizieren und eine mathematische Funktion darauf ausführen. Sie können das ursprüngliche Objekt auch projizieren, ohne es zu ändern.
Von Bedeutung
In diesen Beispielen wird eine System.Collections.Generic.IEnumerable<T>-Datenquelle verwendet. Datenquellen, die auf System.Linq.IQueryProvider basieren, verwenden System.Linq.IQueryable<T>-Datenquellen und Ausdrucksbaumstrukturen. Ausdrucksbaumstrukturen haben Einschränkungen für die zulässige C#-Syntax. Darüber hinaus kann jede IQueryProvider
-Datenquelle, z. B. EF Core, weitere Einschränkungen erzwingen. Konsultieren Sie die Dokumentation für Ihre Datenquelle.
Die Standardmäßigen Abfrageoperatormethoden, die Projektion ausführen, sind im folgenden Abschnitt aufgeführt.
Methodik
Methodennamen | BESCHREIBUNG | Syntax des C#-Abfrageausdrucks | Mehr Informationen |
---|---|---|---|
Auswählen | Projiziert Werte, die auf einer Transformationsfunktion basieren. | select |
Enumerable.Select Queryable.Select |
SelectMany | Projiziert Sequenzen von Werten, die auf einer Transform-Funktion basieren, und fasst diese dann in eine Sequenz zusammen. | Verwenden mehrerer from Klauseln |
Enumerable.SelectMany Queryable.SelectMany |
Schwirren | Erzeugt eine Abfolge von Tupeln mit Elementen aus 2-3 angegebenen Sequenzen. | Nicht zutreffend. | Enumerable.Zip Queryable.Zip |
Select
Im folgenden Beispiel wird die select
Klausel verwendet, um den ersten Buchstaben aus jeder Zeichenfolge in einer Liste von Zeichenfolgen zu projizieren.
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
*/
Die entsprechende Abfrage mit Methodensyntax ist im folgenden Code dargestellt:
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
Im folgenden Beispiel werden mehrere from
Klauseln verwendet, um jedes Wort aus jeder Zeichenfolge in einer Liste von Zeichenfolgen zu projizieren.
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
*/
Die entsprechende Abfrage mit Methodensyntax ist im folgenden Code dargestellt:
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
*/
Die SelectMany
-Methode kann auch die Kombination bilden, die jedes Element der ersten Sequenz mit jedem Element der zweiten Sequenz verbindet.
var query = from number in numbers
from letter in letters
select (number, letter);
foreach (var item in query)
{
Console.WriteLine(item);
}
Die entsprechende Abfrage mit Methodensyntax ist im folgenden Code dargestellt:
var method = numbers
.SelectMany(number => letters,
(number, letter) => (number, letter));
foreach (var item in method)
{
Console.WriteLine(item);
}
Zip
Für den Zip
-Projektionsoperator gibt es mehrere Überladungen.
Zip
Alle Methoden arbeiten an Sequenzen von zwei oder mehr möglicherweise heterogenen Typen. Die ersten beiden Überladungen geben Tupel mit dem entsprechenden Positionstyp aus den angegebenen Sequenzen zurück.
Berücksichtigen Sie die folgenden Sammlungen:
// 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'];
Verwenden Sie den Enumerable.Zip<TFirst,TSecond>(IEnumerable<TFirst>, IEnumerable<TSecond>) Operator, um diese Sequenzen zusammen zu projizieren:
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'
Von Bedeutung
Die resultierende Sequenz eines ZIP-Vorgangs ist nie länger als die kürzeste Sequenz. Die Sammlungen numbers
und letters
unterscheiden sich in der Länge. In der resultierenden Sequenz wird das letzte Element aus der Sammlung numbers
ausgelassen, weil ihm eine Entsprechung fehlt.
Die zweite Überladung akzeptiert eine third
Sequenz. Erstellen wir eine weitere Sammlung, nämlich emoji
:
// A string array with 8 elements.
IEnumerable<string> emoji = [ "🤓", "🔥", "🎉", "👀", "⭐", "💜", "✔", "💯"];
Verwenden Sie den Enumerable.Zip<TFirst,TSecond,TThird>(IEnumerable<TFirst>, IEnumerable<TSecond>, IEnumerable<TThird>) Operator, um diese Sequenzen zusammen zu projizieren:
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: 💜
Ähnlich wie bei der vorherigen Überladung projiziert die Zip
Methode ein Tupel, diesmal aber mit drei Elementen.
Die dritte Überladung akzeptiert ein Func<TFirst, TSecond, TResult>
Argument, das als Ergebnisauswahl fungiert. Sie können eine neue resultierende Sequenz aus den gezippten Sequenzen projizieren.
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)
Bei der vorherigen Zip
-Überladung wird die angegebene Funktion auf die entsprechenden Elemente number
und letter
angewendet, wodurch eine Abfolge von string
-Ergebnissen erzeugt wird.
Select
im Vergleich zu SelectMany
Die Arbeit von beiden Select
und SelectMany
besteht darin, einen Ergebniswert (oder Werte) aus Quellwerten zu erzeugen.
Select
erzeugt einen Ergebniswert für jeden Quellwert. Das Gesamtergebnis ist daher eine Auflistung mit der gleichen Anzahl von Elementen wie die Quellauflistung. Im Gegensatz dazu erzeugt SelectMany
ein einzelnes Gesamtergebnis, das verkettete Teilkollektionen aus jedem Quellwert enthält. Die Transformationsfunktion, die als Argument an SelectMany
übergeben wird, muss eine aufzählbare Abfolge von Werten für jeden Quellwert zurückgeben.
SelectMany
verkettet diese aufzählbaren Sequenzen, um eine große Sequenz zu erstellen.
Die folgenden beiden Abbildungen zeigen den konzeptionellen Unterschied zwischen den Aktionen dieser beiden Methoden. Gehen Sie in jedem Fall davon aus, dass die Selektorfunktion (Transformation) das Array von Blumen aus jedem Quellwert auswählt.
Diese Abbildung zeigt, wie Select
eine Auflistung zurückgegeben wird, die dieselbe Anzahl von Elementen wie die Quellauflistung aufweist.
In dieser Abbildung wird dargestellt, wie SelectMany
die Zwischenabfolge von Arrays in einen Endergebniswert verkettet wird, der jeden Wert aus jedem Zwischenarray enthält.
Codebeispiel
Im folgenden Beispiel wird das Verhalten von Select
und SelectMany
verglichen. Der Code erstellt ein "Blumenstrauß", indem die Elemente aus jeder Liste der Blumennamen in der Quellsammlung entnommen werden. Im folgenden Beispiel ist der von der Transformationsfunktion Select<TSource,TResult>(IEnumerable<TSource>, Func<TSource,TResult>) verwendete einzelne Wert eine Sammlung von Werten. In diesem Beispiel wird die zusätzliche foreach
Schleife benötigt, um jede Zeichenfolge in jeder Teilfolge einzeln aufzuzählen.
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);
}
}