Abfrage einer Auflistung von Objekten
Die Bezeichnung „LINQ to Objects“ bezieht sich auf die direkte Verwendung von LINQ-Abfragen mit einer beliebigen IEnumerable- oder IEnumerable<T>-Auflistung, ohne einen LINQ-Zwischenanbieter oder eine API wie LINQ to SQL oder LINQ to XML zu verwenden. Sie können LINQ zur Abfrage beliebiger aufzählbarer Auflistungen wie List<T>, Array oder Dictionary<TKey,TValue> verwenden. Die Sammlung kann benutzerdefiniert sein oder von einer .NET-API zurückgegeben werden. Im LINQ-Ansatz verfassen Sie einen deklarativen Code, in dem beschrieben wird, was Sie abrufen möchten.
Zudem bieten LINQ-Abfragen drei wesentliche Vorteile gegenüber herkömmlichen foreach
-Schleifen:
- Sie sind präziser und lesbarer, insbesondere beim Filtern mehrerer Bedingungen.
- Sie bieten mit minimalem Anwendungscode leistungsstarke Filter-, Sortier- und Gruppierungsfunktionen.
- Sie können mit geringfügigen oder ohne Änderungen zu anderen Datenquellen portiert werden.
Je komplexer der für die Daten durchzuführende Vorgang, desto größer ist im Allgemeinen der Vorteil, den Sie durch die Verwendung von LINQ anstelle der herkömmlichen Iterationsverfahren haben.
In diesem Beispiel wird veranschaulicht, wie eine einfache Abfrage für eine Liste von Student
-Objekten ausgeführt wird. Jedes Student
-Objekt enthält grundlegende Informationen über den Studenten und eine Liste, die die Ergebnisse des Studenten aus vier Prüfungen darstellt.
Hinweis
Viele andere Beispiele in diesem Abschnitt verwenden dieselbe Student
-Klasse und students
-Auflistung.
class Student
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int ID { get; set; }
public GradeLevel? Year { get; set; }
public List<int> ExamScores { get; set; }
public Student(string FirstName, string LastName, int ID, GradeLevel Year, List<int> ExamScores)
{
this.FirstName = FirstName;
this.LastName = LastName;
this.ID = ID;
this.Year = Year;
this.ExamScores = ExamScores;
}
public Student(string FirstName, string LastName, int StudentID, List<int>? ExamScores = null)
{
this.FirstName = FirstName;
this.LastName = LastName;
ID = StudentID;
this.ExamScores = ExamScores ?? [];
}
public static List<Student> students =
[
new(
FirstName: "Terry", LastName: "Adams", ID: 120,
Year: GradeLevel.SecondYear,
ExamScores: [99, 82, 81, 79]
),
new(
"Fadi", "Fakhouri", 116,
GradeLevel.ThirdYear,
[99, 86, 90, 94]
),
new(
"Hanying", "Feng", 117,
GradeLevel.FirstYear,
[93, 92, 80, 87]
),
new(
"Cesar", "Garcia", 114,
GradeLevel.FourthYear,
[97, 89, 85, 82]
),
new(
"Debra", "Garcia", 115,
GradeLevel.ThirdYear,
[35, 72, 91, 70]
),
new(
"Hugo", "Garcia", 118,
GradeLevel.SecondYear,
[92, 90, 83, 78]
),
new(
"Sven", "Mortensen", 113,
GradeLevel.FirstYear,
[88, 94, 65, 91]
),
new(
"Claire", "O'Donnell", 112,
GradeLevel.FourthYear,
[75, 84, 91, 39]
),
new(
"Svetlana", "Omelchenko", 111,
GradeLevel.SecondYear,
[97, 92, 81, 60]
),
new(
"Lance", "Tucker", 119,
GradeLevel.ThirdYear,
[68, 79, 88, 92]
),
new(
"Michael", "Tucker", 122,
GradeLevel.FirstYear,
[94, 92, 91, 91]
),
new(
"Eugene", "Zabokritski", 121,
GradeLevel.FourthYear,
[96, 85, 91, 60]
)
];
}
enum GradeLevel
{
FirstYear = 1,
SecondYear,
ThirdYear,
FourthYear
};
Beispiel
Die folgende Abfrage gibt die Studenten zurück, die ein Ergebnis von 90 oder höher in ihrer ersten Prüfung erzielt haben.
void QueryHighScores(int exam, int score)
{
var highScores =
from student in students
where student.ExamScores[exam] > score
select new
{
Name = student.FirstName,
Score = student.ExamScores[exam]
};
foreach (var item in highScores)
{
Console.WriteLine($"{item.Name,-15}{item.Score}");
}
}
QueryHighScores(0, 90);
Diese Abfrage wurde absichtlich einfach gehalten, damit Sie damit experimentieren können. Sie können z.B. weitere Bedingungen in der where
-Klausel ausprobieren oder eine orderby
-Klausel verwenden, um die Ergebnisse zu sortieren.
Klassifizierung von Standardabfrageoperatoren nach der Art der Ausführung
Die LINQ to Objects-Implementierungen des Standardabfrageoperators werden mit einer von zwei möglichen Arten ausgeführt: direkt oder zurückgestellt. Abfrageoperatoren, die die verzögerte Ausführung verwenden, können darüber hinaus in zwei Kategorien unterteilt werden: Streaming und Nicht-Streaming. Wenn Sie wissen, wie die einzelnen Abfrageoperatoren ausgeführt werden, erleichtert dies das Verständnis der Ergebnisse, die Sie von einer Abfrage erhalten. Dies ist insbesondere dann der Fall, wenn die Datenquelle geändert wird oder wenn Sie eine Abfrage auf Grundlage einer anderen Abfrage erstellen. In diesem Thema werden die Standardabfrageoperatoren gemäß ihrer Ausführungsarten klassifiziert.
Direkt
Sofortige Ausführung bedeutet, dass die Datenquelle gelesen und die Operation ein Mal ausgeführt wird. Alle Standardabfrageoperatoren, die ein skalares Ergebnis zurückgeben, werden sofort ausgeführt. Sie können erzwingen, dass eine Abfrage sofort ausgeführt wird, indem Sie die Enumerable.ToList- oder Enumerable.ToArray-Methode verwenden. Die sofortige Ausführung ermöglicht die Wiederverwendung von Abfrageergebnissen, aber keine Wiederverwendung der Abfragedeklaration. Die Ergebnisse werden einmal abgerufen und dann für die zukünftige Verwendung gespeichert.
Zurückgestellt
Zurückgestellte Ausführung bedeutet, dass der Vorgang nicht zum Zeitpunkt im Code ausgeführt wird, an dem die Abfrage deklariert wird. Der Vorgang erfolgt nur, wenn die Abfragevariable aufgezählt wird, z.B. durch Verwendung einer foreach
-Anweisung. Dies bedeutet, dass die Ergebnisse der Ausführung der Abfrage vom Inhalt der Datenquelle zum Zeitpunkt der Abfrageausführung, nicht der Abfragedefinition abhängen. Wenn die Abfragevariable mehrfach aufgezählt wird, können die Ergebnisse jedes Mal abweichen. Fast alle Standardabfrageoperatoren, deren Rückgabetyp IEnumerable<T> oder IOrderedEnumerable<TElement> ist, werden verzögert ausgeführt. Die verzögerte Ausführung ermöglicht die Wiederverwendung von Abfragen, da die Abfrage die aktualisierten Daten bei jeder Iteration der Abfrageergebnisse aus der Datenquelle abruft.
Abfrageoperatoren, die die verzögerte Ausführung verwenden, können zusätzlich als Streaming und Nicht-Streaming klassifiziert werden.
Streaming
Streaming-Operatoren müssen nicht alle Quelldaten lesen, bevor sie Elemente liefern. Zum Zeitpunkt der Ausführung führt ein Streaming-Operator seine Operation auf jedem Quellelement aus, während es gelesen wird, und liefert ggf. die Elemente. Ein Streaming-Operator liest weiterhin Quellelemente, bis ein Ergebniselement erzeugt werden kann. Dies bedeutet, dass mehr als ein Quellelement womöglich gelesen werden kann, um ein Ergebniselement zu erzeugen.
Nicht-Streaming
Nicht-Streaming-Operatoren müssen alle Quelldaten lesen, bevor sie ein Ergebniselement liefern können. Vorgänge wie das Sortieren oder Gruppieren fallen unter diese Kategorie. Zum Zeitpunkt der Ausführung lesen Nicht-Streaming-Operatoren alle Quelldaten, fügen sie in eine Datenstruktur ein, führen den Vorgang aus und liefern die Elemente, die sich ergeben.
Klassifizierungstabelle
In der folgenden Tabelle wird jede Standardabfrageoperator-Methode laut der Ausführungsmethode klassifiziert.
Hinweis
Wenn ein Operator in zwei Spalten gekennzeichnet ist, werden zwei Eingabesequenzen in den Vorgang einbezogen, und jede Sequenz wird unterschiedlich ausgewertet. In diesen Fällen ist es immer die erste Sequenz in der Parameterliste, die verzögert und mit der Nicht-Straming-Methode ausgewertet wird.
Siehe auch
Feedback
https://aka.ms/ContentUserFeedback.
Bald verfügbar: Im Laufe des Jahres 2024 werden wir GitHub-Issues stufenweise als Feedbackmechanismus für Inhalte abbauen und durch ein neues Feedbacksystem ersetzen. Weitere Informationen finden Sie unterFeedback senden und anzeigen für