Exemplarische Vorgehensweise: Schreiben von Abfragen in C# (LINQ)

Diese exemplarische Vorgehensweise veranschaulicht die C#-Sprachfunktionen, die zum Schreiben von LINQ-Abfrageausdrücke verwendet werden.

Erstellen eines C#-Projekts

Hinweis

Die folgenden Anweisungen gelten für Visual Studio. Wenn Sie eine andere Entwicklungsumgebung verwenden, erstellen Sie ein Konsolenprojekt mit einem Verweis auf „System.Core.dll“ und eine using-Direktive für den Namespace System.Linq.

So erstellen Sie ein Projekt in Visual Studio

  1. Starten Sie Visual Studio.

  2. Wählen Sie in der Menüleiste Datei, Neu, Projektaus.

    Das Dialogfeld Neues Projekt wird angezeigt.

  3. Erweitern Sie nacheinander Installiert, Vorlagen, Visual C# , und wählen Sie dann Konsolenanwendung aus.

  4. Geben Sie im Textfeld Name einen anderen Namen ein, oder übernehmen Sie den Standardnamen, und wählen Sie dann die Schaltfläche OK aus.

    Das neue Projekt wird im Projektmappen-Explorer angezeigt.

  5. Beachten Sie, dass Ihr Projekt einen Verweis auf „System.Core.dll“ und eine using-Direktive für den Namespace System.Linq enthält.

Erstellen einer In-Memory-Datenquelle

Die Datenquelle für die Abfragen ist eine einfache Liste mit Student-Objekten. Jeder Student-Datensatz umfasst einen Vornamen, einen Nachnamen und ein Array von Ganzzahlen, das die Testergebnisse der einzelnen Studenten in der Klasse darstellt. Kopieren Sie diesen Code in Ihr Projekt. Beachten Sie die folgenden Eigenschaften:

  • Die Student-Klasse besteht aus automatisch implementierten Eigenschaften.

  • Jeder Student in der Liste wird mit einem Objektinitialisierer initialisiert.

  • Die Liste selbst wird mit einem Auflistungsinitialisierer initialisiert.

Die gesamte Datenstruktur wird ohne explizite Aufrufe eines beliebigen Konstruktors oder expliziten Memberzugriff initialisiert und instanziiert. Weitere Informationen zu diesen neuen Funktionen finden Sie unter Automatisch implementierte Eigenschaften und Objekt- und Auflistungsinitialisierer.

So fügen Sie die Datenquelle hinzu

  • Fügen Sie die Student-Klasse und die initialisierte Liste der Studenten zur Program-Klasse in Ihrem Projekt hinzu.

    public class Student
    {
        public string First { get; set; }
        public string Last { get; set; }
        public int ID { get; set; }
        public List<int> Scores;
    }
    
    // Create a data source by using a collection initializer.
    static List<Student> students = 
    [
        new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List<int> {97, 92, 81, 60}},
        new Student {First="Claire", Last="O'Donnell", ID=112, Scores= new List<int> {75, 84, 91, 39}},
        new Student {First="Sven", Last="Mortensen", ID=113, Scores= new List<int> {88, 94, 65, 91}},
        new Student {First="Cesar", Last="Garcia", ID=114, Scores= new List<int> {97, 89, 85, 82}},
        new Student {First="Debra", Last="Garcia", ID=115, Scores= new List<int> {35, 72, 91, 70}},
        new Student {First="Fadi", Last="Fakhouri", ID=116, Scores= new List<int> {99, 86, 90, 94}},
        new Student {First="Hanying", Last="Feng", ID=117, Scores= new List<int> {93, 92, 80, 87}},
        new Student {First="Hugo", Last="Garcia", ID=118, Scores= new List<int> {92, 90, 83, 78}},
        new Student {First="Lance", Last="Tucker", ID=119, Scores= new List<int> {68, 79, 88, 92}},
        new Student {First="Terry", Last="Adams", ID=120, Scores= new List<int> {99, 82, 81, 79}},
        new Student {First="Eugene", Last="Zabokritski", ID=121, Scores= new List<int> {96, 85, 91, 60}},
        new Student {First="Michael", Last="Tucker", ID=122, Scores= new List<int> {94, 92, 91, 91}}
    ];
    

So fügen Sie einen neuen Studenten zur Liste der Studenten hinzu

  1. Fügen Sie einen neuen Student zur Students-Liste hinzu, und verwenden Sie einen Namen und ein Testergebnis Ihrer Wahl. Geben Sie alle Informationen für den neuen Studenten ein, um sich mit der Syntax für den Objektinitialisierer vertraut zu machen.

Erstellen der Abfrage

So erstellen Sie eine einfache Abfrage

  • Erstellen Sie in der Main-Methode der Anwendung eine einfache Abfrage, die bei Ausführung eine Liste aller Studenten erzeugt, deren Ergebnis im ersten Test höher als 90 war. Beachten Sie, dass der Typ der Abfrage Student ist, da das gesamte IEnumerable<Student>-Objekt ausgewählt wird. Obwohl der Code auch die implizite Typisierung mithilfe des Schlüsselworts var verwenden könnte, wird die explizite Typisierung verwendet, um die Ergebnisse deutlich darzustellen. (Weitere Informationen zu var finden Sie unter Implizit typisierte lokale Variablen.)

    Beachten Sie auch, dass student, die Bereichsvariable der Abfrage, als Verweis auf jeden Student in der Quelle dient und Memberzugriff auf jedes Objekt bietet.

// Create the query.
// The first line could also be written as "var studentQuery ="
IEnumerable<Student> studentQuery =
    from student in students
    where student.Scores[0] > 90
    select student;

Ausführen der Abfrage

So führen Sie die Abfrage aus

  1. Schreiben Sie jetzt die foreach-Schleife, die das Ausführen der Abfrage auslöst. Beachten Sie Folgendes beim Code:

    • Auf jedes Element in der zurückgegebenen Sequenz wird über die Iterationsvariable in der foreach-Schleife zugegriffen.

    • Der Typ dieser Variable ist Student, und der Typ der Abfragevariable, IEnumerable<Student>, ist kompatibel.

  2. Erstellen Sie die Anwendung, und führen Sie sie aus, nachdem Sie diesen Code hinzugefügt haben, um die Ergebnisse im Fenster Konsole anzeigen zu lassen.

// Execute the query.
// var could be used here also.
foreach (Student student in studentQuery)
{
    Console.WriteLine("{0}, {1}", student.Last, student.First);
}

// Output:
// Omelchenko, Svetlana
// Garcia, Cesar
// Fakhouri, Fadi
// Feng, Hanying
// Garcia, Hugo
// Adams, Terry
// Zabokritski, Eugene
// Tucker, Michael

So fügen Sie eine weitere Filterbedingung hinzu

  1. Sie können mehrere boolesche Bedingungen in der where-Klausel kombinieren, um eine Abfrage weiter zu optimieren. Der folgende Code fügt eine Bedingung hinzu, sodass die Abfrage die Studenten zurückgibt, deren erstes Ergebnis höher als 90 und das letzte Ergebnis niedriger als 80 war. Die where-Klausel sollte in etwa dem folgenden Code entsprechen.

    where student.Scores[0] > 90 && student.Scores[3] < 80  
    

    Weitere Informationen finden Sie unter where-Klausel.

Ändern der Abfrage

So sortieren Sie die Ergebnisse

  1. Es ist einfacher, die Ergebnisse zu überprüfen, wenn sie geordnet dargestellt werden. Sie können die zurückgegebene Sequenz nach einem beliebigen zugänglichen Feld in den Quellelementen sortieren. Die folgende orderby-Klausel ordnet die Ergebnisse z.B. in alphabetischer Reihenfolge (A bis Z) nach dem Nachnamen jedes Studenten. Fügen Sie die folgende orderby-Klausel direkt nach der where-Anweisung und vor der select-Anweisung zu Ihrer Abfrage hinzu:

    orderby student.Last ascending  
    
  2. Ändern Sie nun die orderby-Klausel so, dass sie die Ergebnisse in umgekehrter Reihenfolge gemäß dem Ergebnis im ersten Test sortiert, vom höchsten zum niedrigsten Ergebnis.

    orderby student.Scores[0] descending  
    
  3. Ändern Sie die WriteLine-Formatzeichenfolge so, dass die Ergebnisse angezeigt werden:

    Console.WriteLine("{0}, {1} {2}", student.Last, student.First, student.Scores[0]);  
    

    Weitere Informationen finden Sie unter orderby-Klausel.

So gruppieren Sie die Ergebnisse

  1. Die Gruppierung ist eine leistungsstarke Funktion in Abfrageausdrücken. Eine Abfrage mit einer group-Klausel erzeugt eine Sequenz von Gruppen, in der jede Gruppe einen Key und eine Sequenz enthält, die aus allen Mitgliedern dieser Gruppe besteht. Die folgende neue Abfrage gruppiert die Studenten mit dem ersten Buchstaben ihres Nachnamens als Schlüssel.

    IEnumerable<IGrouping<char, Student>> studentQuery2 =
        from student in students
        group student by student.Last[0];
    
  2. Beachten Sie, dass sich der Typ der Abfrage jetzt geändert ist. Sie erzeugt nun eine Sequenz von Gruppen mit einem char-Typ als Schlüssel und eine Sequenz von Student-Objekten. Da der Typ der Abfrage geändert wurde, ändert folgender Code ebenfalls die foreach-Ausführungsschleife:

    foreach (IGrouping<char, Student> studentGroup in studentQuery2)
    {
        Console.WriteLine(studentGroup.Key);
        foreach (Student student in studentGroup)
        {
            Console.WriteLine("   {0}, {1}",
                        student.Last, student.First);
        }
    }
    
    // Output:
    // O
    //   Omelchenko, Svetlana
    //   O'Donnell, Claire
    // M
    //   Mortensen, Sven
    // G
    //   Garcia, Cesar
    //   Garcia, Debra
    //   Garcia, Hugo
    // F
    //   Fakhouri, Fadi
    //   Feng, Hanying
    // T
    //   Tucker, Lance
    //   Tucker, Michael
    // A
    //   Adams, Terry
    // Z
    //   Zabokritski, Eugene
    
  3. Führen Sie die Anwendung aus, und zeigen Sie die Ergebnisse im Fenster Konsole an.

    Weitere Informationen finden Sie unter group-Klausel.

So legen Sie Variablen als implizit typisiert fest

  1. Das explizite Codieren von IEnumerables von IGroupings kann schnell mühsam werden. Sie können dieselbe Abfrage und foreach-Schleife viel einfacher mithilfe von var schreiben. Das Schlüsselwort var ändert die Typen Ihres Objekts nicht; es weist nur den Compiler an, die Typen abzuleiten. Ändern Sie den Typ von studentQuery und der Iterationsvariable group zu var, und führen Sie die Abfrage erneut aus. Beachten Sie, dass die Iterationsvariable in der inneren foreach-Schleife immer noch als Student typisiert ist und die Abfrage so ausgeführt wird wie zuvor. Ändern Sie die Iterationsvariable student zu var, und führen Sie die Abfrage erneut aus. Sie sehen, dass Sie genau die gleichen Ergebnisse erhalten.

    var studentQuery3 =
        from student in students
        group student by student.Last[0];
    
    foreach (var groupOfStudents in studentQuery3)
    {
        Console.WriteLine(groupOfStudents.Key);
        foreach (var student in groupOfStudents)
        {
            Console.WriteLine("   {0}, {1}",
                student.Last, student.First);
        }
    }
    
    // Output:
    // O
    //   Omelchenko, Svetlana
    //   O'Donnell, Claire
    // M
    //   Mortensen, Sven
    // G
    //   Garcia, Cesar
    //   Garcia, Debra
    //   Garcia, Hugo
    // F
    //   Fakhouri, Fadi
    //   Feng, Hanying
    // T
    //   Tucker, Lance
    //   Tucker, Michael
    // A
    //   Adams, Terry
    // Z
    //   Zabokritski, Eugene
    

    Weitere Informationen zu var finden Sie unter Implizit typisierte lokale Variablen.

So sortieren Sie die Gruppen nach ihren Schlüsselwerten

  1. Wenn Sie die vorherige Abfrage ausführen, werden Sie feststellen, dass die Gruppen nicht alphabetischer angeordnet sind. Um dies zu ändern, müssen Sie eine orderby-Klausel nach der group-Klausel angeben. Sie benötigen aber zuerst einen Bezeichner, der als Verweis auf die durch die group-Klausel erstellte Gruppe dient, bevor Sie eine orderby-Klausel verwenden können. Geben Sie den Bezeichner mithilfe des Schlüsselworts into wie folgt an:

    var studentQuery4 =
        from student in students
        group student by student.Last[0] into studentGroup
        orderby studentGroup.Key
        select studentGroup;
    
    foreach (var groupOfStudents in studentQuery4)
    {
        Console.WriteLine(groupOfStudents.Key);
        foreach (var student in groupOfStudents)
        {
            Console.WriteLine("   {0}, {1}",
                student.Last, student.First);
        }
    }
    
    // Output:
    //A
    //   Adams, Terry
    //F
    //   Fakhouri, Fadi
    //   Feng, Hanying
    //G
    //   Garcia, Cesar
    //   Garcia, Debra
    //   Garcia, Hugo
    //M
    //   Mortensen, Sven
    //O
    //   Omelchenko, Svetlana
    //   O'Donnell, Claire
    //T
    //   Tucker, Lance
    //   Tucker, Michael
    //Z
    //   Zabokritski, Eugene
    

    Wenn Sie diese Abfrage ausführen, werden Sie feststellen, dass die Gruppen nun in alphabetischer Reihenfolge sortiert sind.

So führen Sie einen Bezeichner mit „let“ ein

  1. Sie können das Schlüsselwort let verwenden, um einen Bezeichner für ein beliebiges Ausdrucksergebnis in den Abfrageausdruck einzuführen. Dieser Bezeichner ist sehr praktisch, wie im folgenden Beispiel zu sehen ist; er kann auch die Leistung verbessern, da die Ergebnisse eines Ausdrucks gespeichert werden und nicht mehrfach berechnet werden müssen.

    // studentQuery5 is an IEnumerable<string>
    // This query returns those students whose
    // first test score was higher than their
    // average score.
    var studentQuery5 =
        from student in students
        let totalScore = student.Scores[0] + student.Scores[1] +
            student.Scores[2] + student.Scores[3]
        where totalScore / 4 < student.Scores[0]
        select student.Last + " " + student.First;
    
    foreach (string s in studentQuery5)
    {
        Console.WriteLine(s);
    }
    
    // Output:
    // Omelchenko Svetlana
    // O'Donnell Claire
    // Mortensen Sven
    // Garcia Cesar
    // Fakhouri Fadi
    // Feng Hanying
    // Garcia Hugo
    // Adams Terry
    // Zabokritski Eugene
    // Tucker Michael
    

    Weitere Informationen finden Sie unter let-Klausel.

So verwenden Sie die Methodensyntax in einem Abfrageausdruck

  1. Wie unter Abfragesyntax und Methodensyntax in LINQ beschrieben, können einige Abfrageoperationen nur durch Verwendung der Methodensyntax ausgedrückt werden. Der folgende Code berechnet das Gesamtergebnis für jeden Student in der Quellsequenz und ruft dann die Average()-Methode für die Ergebnisse der Abfrage auf, um die durchschnittliche Punktzahl der Klasse zu berechnen.

    var studentQuery6 =
        from student in students
        let totalScore = student.Scores[0] + student.Scores[1] +
            student.Scores[2] + student.Scores[3]
        select totalScore;
    
    double averageScore = studentQuery6.Average();
    Console.WriteLine("Class average score = {0}", averageScore);
    
    // Output:
    // Class average score = 334.166666666667
    

So transformieren oder projizieren Sie in die select-Klausel

  1. Es kommt sehr häufig vor, dass eine Abfrage eine Sequenz erzeugt, deren Elemente sich von den Elementen in den Quellsequenzen unterscheiden. Löschen Sie oder kommentieren Sie die vorherige Abfrage und Ausführungsschleife aus, und ersetzen Sie sie durch den folgenden Code. Beachten Sie, dass die Abfrage eine Sequenz von Zeichenfolgen zurückgibt (nicht Students). Dies spiegelt sich in der foreach-Schleife wider.

    IEnumerable<string> studentQuery7 =
        from student in students
        where student.Last == "Garcia"
        select student.First;
    
    Console.WriteLine("The Garcias in the class are:");
    foreach (string s in studentQuery7)
    {
        Console.WriteLine(s);
    }
    
    // Output:
    // The Garcias in the class are:
    // Cesar
    // Debra
    // Hugo
    
  2. Der vorherige Code in dieser exemplarischen Vorgehensweise hat gezeigt, dass das durchschnittliche Ergebnis der Klasse ungefähr 334 beträgt. Zum Erstellen einer Sequenz von Students mit ihrer Student ID, deren Ergebnis höher ist als der Klassendurchschnitt, können Sie einen anonymen Typ in der select-Anweisung verwenden:

Nächste Schritte

Nachdem Sie nun mit den grundlegenden Aspekten der Arbeit mit Abfragen in C# vertraut sind, sind Sie nun bereit, die Dokumentation und Beispiele für bestimmte LINQ-Anbieter zu lesen, an denen Sie interessiert sind:

LINQ to SQL

LINQ to DataSet

LINQ to XML (C#)

LINQ to Objects (C#)

Siehe auch