Freigeben über


Arbeiten mit LINQ (Language-Integrated Query)

Einleitung

In diesem Lernprogramm lernen Sie Features in .NET Core und der C#-Sprache kennen. Sie lernen Folgendes:

  • Generieren Sie Sequenzen mit LINQ.
  • Schreiben Sie Methoden, die in LINQ-Abfragen problemlos verwendet werden können.
  • Unterscheiden Sie zwischen eifriger und fauler Bewertung.

Sie lernen diese Techniken durch Erstellen einer Anwendung, die eine der grundlegenden Fertigkeiten jedes Zauberkünstlers demonstriert: den Faro-Shuffle. Ein Faro-Shuffle ist eine Kartenmischtechnik, bei der zwei Kartenpäckchen exakt so ineinander gefächert werden, dass auf eine Karte des einen Stapels stets eine Karte des anderen Stapels folgt.

Zauberer verwenden diese Technik, da sich jede Karte nach jedem Shuffle an einer bekannten Stelle befindet und die Reihenfolge ein wiederholtes Muster ist.

Für Ihre Zwecke ist es ein humorvoller Blick auf die Manipulation von Datenabfolgen. Die Anwendung, die Sie erstellen, erstellt einen Kartensatz und führt dann eine Sequenz von Shuffles durch, wobei die Sequenz jedes Mal ausgeschrieben wird. Sie vergleichen auch die aktualisierte Bestellung mit der ursprünglichen Bestellung.

Dieses Lernprogramm enthält mehrere Schritte. Nach jedem Schritt können Sie die Anwendung ausführen und den Fortschritt anzeigen. Sie können sich auch das abgeschlossene Beispiel in unserem Repository „dotnet/samples“ auf GitHub ansehen. Anweisungen zum Herunterladen finden Sie unter Beispiele und Lernprogramme.

Voraussetzungen

Erstellen der Anwendung

Der erste Schritt besteht darin, eine neue Anwendung zu erstellen. Öffnen Sie eine Eingabeaufforderung, und erstellen Sie ein neues Verzeichnis für Ihre Anwendung. Legen Sie das Verzeichnis als aktuelles Verzeichnis fest. Geben Sie den Befehl dotnet new console an der Eingabeaufforderung ein. Dadurch werden die Startdateien für eine einfache "Hello World"-Anwendung erstellt.

Wenn Sie C# noch nie verwendet haben, dieses Lernprogramm die Struktur eines C#-Programms erläutert. Sie können das lesen und dann hier zurückkehren, um mehr über LINQ zu erfahren.

Erstellen des Datasets

Bevor Sie beginnen, stellen Sie sicher, dass sich die folgenden Zeilen am Anfang der Program.cs Datei befinden, die von dotnet new consolegeneriert wird:

// Program.cs
using System;
using System.Collections.Generic;
using System.Linq;

Wenn sich diese drei Zeilen (using Direktiven) nicht am Anfang der Datei befinden, wird ihr Programm möglicherweise nicht kompiliert.

Nachdem Sie nun alle benötigten Verweise haben, überlegen Sie, was ein Kartenspiel ausmacht. In der Regel besteht ein Spielkartenstapel aus vier Farben, und jede hat dreizehn Werte. Normalerweise sollten Sie eine Card-Klasse gleich zu Beginn erstellen und eine Sammlung von Card-Objekten manuell auffüllen. Mithilfe von LINQ können Sie prägnanter sein als mit der üblichen Methode, einen Kartenstapel zu erstellen. Anstatt eine Card Klasse zu erstellen, können Sie zwei Sequenzen erstellen, um Anzüge bzw. Rangfolgen darzustellen. Sie erstellen ein einfaches Paar von Iteratormethoden, das die Ränge und Farben als IEnumerable<T>s von Zeichenfolgen generiert:

// Program.cs
// The Main() method

static IEnumerable<string> Suits()
{
    yield return "clubs";
    yield return "diamonds";
    yield return "hearts";
    yield return "spades";
}

static IEnumerable<string> Ranks()
{
    yield return "two";
    yield return "three";
    yield return "four";
    yield return "five";
    yield return "six";
    yield return "seven";
    yield return "eight";
    yield return "nine";
    yield return "ten";
    yield return "jack";
    yield return "queen";
    yield return "king";
    yield return "ace";
}

Platzieren Sie diese unter der Main-Methode in Ihrer Program.cs-Datei. Diese beiden Methoden verwenden die yield return Syntax, um während der Ausführung eine Sequenz zu erzeugen. Der Compiler erstellt ein Objekt, das IEnumerable<T> implementiert und die Abfolge von Zeichenfolgen generiert, sobald sie angefordert werden.

Verwenden Sie nun diese Iteratormethoden, um den Kartensatz zu erstellen. Sie platzieren die LINQ-Abfrage in unserer Main-Methode. Hier ist ein Blick darauf:

// Program.cs
static void Main(string[] args)
{
    var startingDeck = from s in Suits()
                       from r in Ranks()
                       select new { Suit = s, Rank = r };

    // Display each card that we've generated and placed in startingDeck in the console
    foreach (var card in startingDeck)
    {
        Console.WriteLine(card);
    }
}

Die verschiedenen from-Klauseln erzeugen SelectMany, wodurch aus der Kombination jedes Elements in der ersten Sequenz mit jedem Element in der zweiten Sequenz eine einzige Sequenz erstellt wird. Die Bestellung ist für unsere Zwecke wichtig. Das erste Element in der ersten Quellsequenz (Farben) wird mit jedem Element in der zweiten Sequenz (Ränge) kombiniert. Dadurch werden alle dreizehn Karten der ersten Farbe erzeugt. Dieser Vorgang wird mit jedem Element in der ersten Sequenz (Farben) wiederholt. Das Ergebnis ist ein Kartenstapel, der erst nach Farben und innerhalb der Farben nach Werten sortiert ist.

Es ist wichtig zu beachten, dass Sie unabhängig davon, ob Sie ihren LINQ in der oben verwendeten Abfragesyntax schreiben oder stattdessen Methodensyntax verwenden, es ist immer möglich, von einer Form der Syntax zur anderen zu wechseln. Die oben in der Abfragesyntax geschriebene Abfrage kann in der Methodensyntax wie folgt geschrieben werden:

var startingDeck = Suits().SelectMany(suit => Ranks().Select(rank => new { Suit = suit, Rank = rank }));

Der Compiler übersetzt LINQ-Anweisungen, die mit abfragesyntax geschrieben wurden, in die entsprechende Methodenaufrufsyntax. Daher erzeugen die beiden Versionen der Abfrage unabhängig von ihrer Syntax dasselbe Ergebnis. Wählen Sie aus, welche Syntax für Ihre Situation am besten geeignet ist: Wenn Sie beispielsweise in einem Team arbeiten, in dem einige Mitglieder Schwierigkeiten mit der Methodensyntax haben, versuchen Sie, die Verwendung der Abfragesyntax zu bevorzugen.

Fahren Sie fort, und führen Sie das Beispiel aus, das Sie zu diesem Zeitpunkt erstellt haben. Es werden alle 52 Karten im Deck angezeigt. Möglicherweise ist es sehr hilfreich, dieses Beispiel unter einem Debugger auszuführen, um zu beobachten, wie die methoden Suits() und Ranks() ausgeführt werden. Sie können deutlich erkennen, dass jede Zeichenfolge in jeder Sequenz nur generiert wird, wenn sie benötigt wird.

Ein Konsolenfenster, in dem die App 52 Karten ausgeschrieben hat.

Ändern der Reihenfolge

Konzentrieren Sie sich nun darauf, wie die Karten im Kartenstapel gemischt werden sollen. Der erste Schritt bei jedem guten Mischen ist das Aufteilen des Kartenstapels in zwei Hälften. Die methoden Take und Skip, die Teil der LINQ-APIs sind, stellen dieses Feature für Sie bereit. Platzieren Sie sie unter der foreach Schleife:

// Program.cs
public static void Main(string[] args)
{
    var startingDeck = from s in Suits()
                       from r in Ranks()
                       select new { Suit = s, Rank = r };

    foreach (var c in startingDeck)
    {
        Console.WriteLine(c);
    }

    // 52 cards in a deck, so 52 / 2 = 26
    var top = startingDeck.Take(26);
    var bottom = startingDeck.Skip(26);
}

In der Standardbibliothek ist jedoch keine Mischmethode vorhanden, Sie müssen sie also selbst schreiben. Die shuffle-Methode, die Sie erstellen, veranschaulicht verschiedene Techniken, die Sie mit LINQ-basierten Programmen verwenden, sodass jeder Teil dieses Prozesses in Schritten erläutert wird.

Um Funktionalität für Ihre Interaktion mit den IEnumerable<T>-Formen, die Sie von einigen LINQ-Abfragen erhalten, hinzuzufügen, müssen Sie einige besondere Arten von Methoden schreiben, die als Erweiterungsmethoden bezeichnet werden. Eine Erweiterungsmethode ist im Wesentlichen eine statische Methode für einen speziellen Zweck, die einem bereits vorhandenen Typ Funktionalität hinzufügt, ohne diesen ursprünglichen Typ ändern zu müssen.

Verleihen Sie Ihren Erweiterungsmethoden ein neues Zuhause, indem Sie ihrem Programm eine neue statische Klassendatei hinzufügen, die Extensions.csgenannt wird, und beginnen Sie dann mit dem Erstellen der ersten Erweiterungsmethode:

// Extensions.cs
using System;
using System.Collections.Generic;
using System.Linq;

namespace LinqFaroShuffle
{
    public static class Extensions
    {
        public static IEnumerable<T> InterleaveSequenceWith<T>(this IEnumerable<T> first, IEnumerable<T> second)
        {
            // Your implementation will go here soon enough
        }
    }
}

Sehen Sie sich die Methodensignatur für einen Moment an, insbesondere die Parameter:

public static IEnumerable<T> InterleaveSequenceWith<T> (this IEnumerable<T> first, IEnumerable<T> second)

Sie können sehen, dass der this Modifizierer zum ersten Argument der Methode hinzugefügt wurde. Dies bedeutet, dass Sie die Methode so aufrufen können, als wäre sie eine Membermethode vom Typ des ersten Arguments. Diese Methodendeklaration folgt auch einem Standardidiom, bei dem die Eingabe- und Ausgabetypen IEnumerable<T>sind. In dieser Praxis können LINQ-Methoden verkettet werden, um komplexere Abfragen auszuführen.

Da Sie den Deck natürlich in Hälften aufteilen, müssen Sie diese Hälften miteinander verbinden. Im Code zählen Sie beide Sequenzen, die Sie durch Take und Skip erhalten haben, gleichzeitig auf, führen ein interleaving der Elemente durch und erstellen eine einzige Sequenz: Ihr jetzt gemischter Kartenstapel. Das Schreiben einer LINQ-Methode, die mit zwei Sequenzen funktioniert, erfordert, dass Sie verstehen, wie IEnumerable<T> funktioniert.

Die IEnumerable<T>-Schnittstelle hat eine Methode: GetEnumerator. Das von GetEnumerator zurückgegebene Objekt verfügt über eine Methode, um zum nächsten Element zu wechseln, und eine Eigenschaft, die das aktuelle Element in der Sequenz abruft. Sie verwenden diese beiden Member, um die Auflistung aufzuzählen und die Elemente zurückzugeben. Diese Interleave-Methode ist eine Iteratormethode. Statt eine Sammlung zu erstellen und die Auflistung zurückzugeben, verwenden Sie die oben gezeigte yield return Syntax.

Dies ist die Implementierung dieser Methode:

public static IEnumerable<T> InterleaveSequenceWith<T>
    (this IEnumerable<T> first, IEnumerable<T> second)
{
    var firstIter = first.GetEnumerator();
    var secondIter = second.GetEnumerator();

    while (firstIter.MoveNext() && secondIter.MoveNext())
    {
        yield return firstIter.Current;
        yield return secondIter.Current;
    }
}

Nachdem Sie diese Methode geschrieben haben, wechseln Sie zurück zur Main-Methode, und mischen Sie das Deck einmal:

// Program.cs
public static void Main(string[] args)
{
    var startingDeck = from s in Suits()
                       from r in Ranks()
                       select new { Suit = s, Rank = r };

    foreach (var c in startingDeck)
    {
        Console.WriteLine(c);
    }

    var top = startingDeck.Take(26);
    var bottom = startingDeck.Skip(26);
    var shuffle = top.InterleaveSequenceWith(bottom);

    foreach (var c in shuffle)
    {
        Console.WriteLine(c);
    }
}

Vergleiche

Wie viele Mischvorgänge dauert es, um das Deck in seine ursprüngliche Reihenfolge zurückzubringen? Um herauszufinden, müssen Sie eine Methode schreiben, die bestimmt, ob zwei Sequenzen gleich sind. Nachdem Sie diese Methode erstellt haben, müssen Sie den Code, der den Stapel mischt, in eine Schleife platzieren und dann prüfen, wann der Stapel wieder die ursprüngliche Reihenfolge aufweist.

Das Schreiben einer Methode, um festzustellen, ob die beiden Sequenzen gleich sind, sollte einfach sein. Die Methode hat die gleiche Struktur wie die Methode, die Sie zum Mischen des Kartenstapels geschrieben haben. Der Unterschied ist, dass dieses Mal nicht für jedes Element ein yield return ausgeführt wird, sondern dass Sie die übereinstimmenden Elemente jeder Sequenz vergleichen. Wenn die gesamte Sequenz aufgezählt wurde, wenn jedes Element übereinstimmt, sind die Sequenzen identisch:

public static bool SequenceEquals<T>
    (this IEnumerable<T> first, IEnumerable<T> second)
{
    var firstIter = first.GetEnumerator();
    var secondIter = second.GetEnumerator();

    while ((firstIter?.MoveNext() == true) && secondIter.MoveNext())
    {
        if ((firstIter.Current is not null) && !firstIter.Current.Equals(secondIter.Current))
        {
            return false;
        }
    }

    return true;
}

Dies zeigt ein zweites LINQ-Idiom: Terminalmethoden. Sie nehmen eine Sequenz als Eingabe (oder in diesem Fall zwei Sequenzen) und geben einen einzelnen skalaren Wert zurück. Bei der Verwendung von Terminalmethoden sind sie immer die endgültige Methode in einer Kette von Methoden für eine LINQ-Abfrage, daher der Name "terminal".

Sie können dies in der Praxis sehen, wenn Sie es verwenden, um zu bestimmen, wann sich das Kartendeck wieder in der ursprünglichen Reihenfolge befindet. Platzieren Sie den Shuffle-Code in einer Schleife, und beenden Sie den Vorgang, wenn die Sequenz wieder in der ursprünglichen Reihenfolge liegt, indem Sie die SequenceEquals()-Methode anwenden. Sie können sehen, dass es immer die endgültige Methode in jeder Abfrage ist, da sie einen einzelnen Wert anstelle einer Sequenz zurückgibt:

// Program.cs
static void Main(string[] args)
{
    // Query for building the deck

    // Shuffling using InterleaveSequenceWith<T>();

    var times = 0;
    // We can re-use the shuffle variable from earlier, or you can make a new one
    shuffle = startingDeck;
    do
    {
        shuffle = shuffle.Take(26).InterleaveSequenceWith(shuffle.Skip(26));

        foreach (var card in shuffle)
        {
            Console.WriteLine(card);
        }
        Console.WriteLine();
        times++;

    } while (!startingDeck.SequenceEquals(shuffle));

    Console.WriteLine(times);
}

Führen Sie den bisher erstellten Code aus, und notieren Sie sich, wie der Kartenstapel bei jedem Mischvorgang neu angeordnet wird. Nach 8 Mischvorgängen (Iterationen der Do-while-Schleife) kehrt der Stapel zur ursprünglichen Konfiguration zurück, die er hatte, als Sie ihn zum ersten Mal durch Starten der LINQ-Abfrage erstellt haben.

Optimierungen

Das Beispiel, das Sie bisher erstellt haben, führt einen Mischvorgang nach außen aus, bei dem die oberste und unterste Karte bei jedem Durchgang gleich bleiben. Nehmen wir eine Änderung vor: Wir verwenden stattdessen eine in shuffle, wobei alle 52 Karten die Position ändern. Hierbei werden die Hälften so ineinander gefächert, dass die erste Karte der unteren Hälfte zur ersten Karte des Kartenstapels wird. Das bedeutet, dass die letzte Karte in der oberen Hälfte zur unteren Karte wird. Dies ist eine einfache Änderung an einer einzelnen Codezeile. Aktualisieren Sie die aktuelle Shuffle-Abfrage, indem Sie die Positionen von Take und Skipwechseln. Dadurch wird die Reihenfolge der oberen und unteren Hälften des Decks geändert:

shuffle = shuffle.Skip(26).InterleaveSequenceWith(shuffle.Take(26));

Führen Sie das Programm erneut aus, und Sie sehen, dass es 52 Iterationen dauert, bis sich das Deck neu anordnen kann. Sie werden auch einige erhebliche Leistungsabfälle beim Ausführen des Programms bemerken.

Hierfür gibt es eine Reihe von Gründen. Sie können eine der wichtigsten Ursachen dieses Leistungsabfalls bekämpfen: die ineffiziente Nutzung der verzögerten Auswertung.

Der wesentliche Aspekt der verzögerten Auswertung ist, dass eine Anweisung erst dann ausgewertet wird, wenn der Wert benötigt wird. LINQ-Abfragen sind verzögert ausgewertete Anweisungen. Die Sequenzen werden nur generiert, wenn die Elemente angefordert werden. In der Regel ist das ein großer Vorteil von LINQ. In einer Verwendung wie diesem Programm führt dies jedoch zu exponentiellem Wachstum in der Ausführungszeit.

Denken Sie daran, dass wir den ursprünglichen Kartensatz mithilfe einer LINQ-Abfrage generiert haben. Jede Shuffle wird durch Ausführen von drei LINQ-Abfragen auf dem vorherigen Deck generiert. All diese werden verzögert ausgeführt. Das bedeutet auch, dass sie jedes Mal erneut ausgeführt werden, wenn die Sequenz angefordert wird. Wenn Sie zur 52. Iteration gelangen, regenerieren Sie das ursprüngliche Deck viele Male neu. Schreiben wir ein Protokoll, um dieses Verhalten zu veranschaulichen. Dann werden Sie es beheben.

Geben Sie in Ihrer Extensions.cs-Datei die folgende Methode ein, oder kopieren Sie sie. Diese Erweiterungsmethode erstellt eine neue Datei namens debug.log in Ihrem Projektverzeichnis und zeichnet auf, welche Abfrage derzeit in der Protokolldatei ausgeführt wird. Diese Erweiterungsmethode kann an jede Abfrage angefügt werden, um die ausgeführte Abfrage zu markieren.

public static IEnumerable<T> LogQuery<T>
    (this IEnumerable<T> sequence, string tag)
{
    // File.AppendText creates a new file if the file doesn't exist.
    using (var writer = File.AppendText("debug.log"))
    {
        writer.WriteLine($"Executing Query {tag}");
    }

    return sequence;
}

Dann werden unter File rote Wellenlinien angezeigt. Das bedeutet, dass dieses Element nicht vorhanden ist. Es wird nicht kompiliert, da der Compiler nicht weiß, was File ist. Um dieses Problem zu beheben, müssen Sie die folgende Codezeile in der ersten Zeile in Extensions.cshinzufügen:

using System.IO;

Dies sollte das Problem lösen und der rote Fehler verschwindet.

Instrumentieren Sie als Nächstes die Definition jeder Abfrage mit einer Protokollmeldung:

// Program.cs
public static void Main(string[] args)
{
    var startingDeck = (from s in Suits().LogQuery("Suit Generation")
                        from r in Ranks().LogQuery("Rank Generation")
                        select new { Suit = s, Rank = r }).LogQuery("Starting Deck");

    foreach (var c in startingDeck)
    {
        Console.WriteLine(c);
    }

    Console.WriteLine();
    var times = 0;
    var shuffle = startingDeck;

    do
    {
        // Out shuffle
        /*
        shuffle = shuffle.Take(26)
            .LogQuery("Top Half")
            .InterleaveSequenceWith(shuffle.Skip(26)
            .LogQuery("Bottom Half"))
            .LogQuery("Shuffle");
        */

        // In shuffle
        shuffle = shuffle.Skip(26).LogQuery("Bottom Half")
                .InterleaveSequenceWith(shuffle.Take(26).LogQuery("Top Half"))
                .LogQuery("Shuffle");

        foreach (var c in shuffle)
        {
            Console.WriteLine(c);
        }

        times++;
        Console.WriteLine(times);
    } while (!startingDeck.SequenceEquals(shuffle));

    Console.WriteLine(times);
}

Beachten Sie, dass Sie nicht jedes Mal protokollieren, wenn Sie auf eine Abfrage zugreifen. Sie protokollieren nur, wenn Sie die ursprüngliche Abfrage erstellen. Das Programm dauert immer noch lange, aber jetzt können Sie sehen, warum. Wenn Sie nicht warten möchten, bis das Mischen nach innen mit aktivierter Protokollierung ausgeführt wurde, wechseln Sie zurück zum Mischen nach außen. Sie werden weiterhin die Effekte der trägen Auswertung sehen. In einer Ausführung werden 2592 Abfragen ausgeführt, einschließlich der Generierung aller Werte und Farben.

Sie können die Leistung des Codes hier verbessern, um die Anzahl der ausgeführten Ausführungen zu verringern. Eine einfache Lösung ist das Zwischenspeichern der Ergebnisse der ursprünglichen LINQ-Abfrage, die den Kartenstapel erstellt. Derzeit führen Sie die Abfragen jedes Mal erneut aus, wenn die Do-while-Schleife eine Iteration durchläuft, wobei Sie jedes Mal den Kartenstapel neu erstellen und mischen. Um den Kartensatz zwischenzuspeichern, können Sie die LINQ-Methoden ToArray und ToListnutzen; Wenn Sie sie an die Abfragen anfügen, führen sie dieselben Aktionen aus, denen Sie sie mitgeteilt haben, aber jetzt speichern sie die Ergebnisse in einem Array oder einer Liste, je nachdem, welche Methode Sie aufrufen möchten. Fügen Sie die LINQ-Methode ToArray an beide Abfragen an, und führen Sie das Programm erneut aus:

public static void Main(string[] args)
{
    IEnumerable<Suit>? suits = Suits();
    IEnumerable<Rank>? ranks = Ranks();

    if ((suits is null) || (ranks is null))
        return;

    var startingDeck = (from s in suits.LogQuery("Suit Generation")
                        from r in ranks.LogQuery("Value Generation")
                        select new { Suit = s, Rank = r })
                        .LogQuery("Starting Deck")
                        .ToArray();

    foreach (var c in startingDeck)
    {
        Console.WriteLine(c);
    }

    Console.WriteLine();

    var times = 0;
    var shuffle = startingDeck;

    do
    {
        /*
        shuffle = shuffle.Take(26)
            .LogQuery("Top Half")
            .InterleaveSequenceWith(shuffle.Skip(26).LogQuery("Bottom Half"))
            .LogQuery("Shuffle")
            .ToArray();
        */

        shuffle = shuffle.Skip(26)
            .LogQuery("Bottom Half")
            .InterleaveSequenceWith(shuffle.Take(26).LogQuery("Top Half"))
            .LogQuery("Shuffle")
            .ToArray();

        foreach (var c in shuffle)
        {
            Console.WriteLine(c);
        }

        times++;
        Console.WriteLine(times);
    } while (!startingDeck.SequenceEquals(shuffle));

    Console.WriteLine(times);
}

Jetzt ist der Mischvorgang nach außen auf 30 Abfragen reduziert. Auch beim Mischen nach innen werden Sie ähnliche Verbesserungen feststellen: Jetzt werden 162 Abfragen ausgeführt.

Beachten Sie, dass dieses Beispiel entwickelt wurde, um die Anwendungsfälle hervorzuheben, in denen eine faule Auswertung zu Leistungsproblemen führen kann. Obwohl es wichtig ist, zu sehen, wo sich die faule Auswertung auf die Codeleistung auswirken kann, ist es ebenso wichtig zu verstehen, dass nicht alle Abfragen eifrig ausgeführt werden sollten. Die Leistungsbeeinträchtigung, die auftritt, ohne ToArray zu verwenden, entsteht dadurch, dass jede neue Anordnung des Kartendecks aus der vorherigen Anordnung erstellt wird. Die Verwendung von Lazy Evaluation bedeutet, dass jede neue Deckkonfiguration aus dem ursprünglichen Deck erstellt wird und sogar den Code ausführt, der die startingDeckgeneriert hat. Dies führt zu einer großen Menge zusätzlicher Arbeit.

In der Praxis laufen einige Algorithmen gut mit eifriger Auswertung, und andere laufen gut mit fauler Auswertung. Für die tägliche Nutzung ist Lazy Evaluation in der Regel die bessere Wahl, wenn die Datenquelle ein separater Prozess ist, z. B. eine Datenbank-Engine. Bei Datenbanken ermöglicht die verzögerte Auswertung komplexere Abfragen, um nur einen Roundtrip zum Datenbankprozess und zurück zu Ihrem übrigen Code auszuführen. LINQ ist flexibel, unabhängig davon, ob Sie Lazy-Evaluation oder Eager-Evaluation nutzen möchten. Messen Sie Ihre Prozesse und wählen Sie aus, welche Art von Auswertung Ihnen die beste Leistung bietet.

Schlussfolgerung

In diesem Projekt haben Sie Folgendes behandelt:

  • Verwenden von LINQ-Abfragen zum Aggregieren von Daten in einer sinnvollen Sequenz
  • Schreiben von Erweiterungsmethoden zum Hinzufügen unserer eigenen benutzerdefinierten Funktionalität zu LINQ-Abfragen
  • Ermitteln von Bereichen in unserem Code, in denen unsere LINQ-Abfragen möglicherweise Leistungsprobleme wie beeinträchtigte Geschwindigkeit haben
  • verzögerte und strikte Auswertung im Hinblick auf die LINQ-Abfragen und die möglichen Auswirkungen auf die Abfrageleistung

Abgesehen von LINQ haben Sie etwas über eine Technik gelernt, die Zauberer für Kartentricks verwenden. Zauberer verwenden den Faro-Shuffle, weil sie steuern können, wo sich jede Karte im Deck bewegt. Jetzt, da Sie es wissen, verraten Sie es nicht allen anderen!

Weitere Informationen zu LINQ finden Sie unter: