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.
Wählen Sie einen Iterator aus, wenn Sie eine Sequenz zurückgeben möchten, deren Elemente Aufrufer einzeln nutzen können, ohne zuerst das vollständige Ergebnis in einer Auflistung zu erstellen. Dieser Ansatz eignet sich für generierte Werte, Filter mit benutzerdefiniertem Kontrollfluss und Sequenzen, deren Auslesung vom Aufrufer vorzeitig abgebrochen werden könnte. Im Vergleich zu einer abgeschlossenen Sammlung ändert sich bei einem Iterator der Zeitpunkt der Ausführung, nicht nur die Art und Weise, wie man ihn schreibt.
Tip
In diesem Artikel werden synchrone Iteratoren für Entwickler erklärt, die Methoden, Schleifen und Sammlungen kennen. Vollständige yield Syntax und Einschränkungen finden Sie in der yield Anweisungsreferenz.
Eine Iteratormethode liefert Werte nacheinander. Dieser Artikel konzentriert sich auf Iterator-Methoden, die IEnumerable<T> zurückgeben, deren Werte Aufrufer in der Regel mit einer foreach-Anweisung verwenden.
Elemente mit yield return erzeugen
Wird verwendet yield return , um das nächste Element in der Sequenz bereitzustellen. Im folgenden Iterator werden akzeptable Temperaturwerte von einem Sensor ausgewählt. In diesem Szenario markiert -1 das Ende der Sensordaten.
int[] readings = [21, 27, 24, -1, 19];
IEnumerable<int> acceptedReadings =
SelectTemperatures(readings, maximum: 25);
Console.WriteLine("Sequence created.");
foreach (int temperature in acceptedReadings)
{
Console.WriteLine($"Accepted: {temperature}°C");
}
static IEnumerable<int> SelectTemperatures(
IEnumerable<int> readings,
int maximum)
{
foreach (int reading in readings)
{
Console.WriteLine($"Checking {reading}°C");
if (reading == -1)
{
yield break;
}
if (reading <= maximum)
{
yield return reading;
}
}
}
SelectTemperatures gibt IEnumerable<int>zurück, das eine Abfolge von int Werten darstellt. Jedes yield return reading stellt einen Wert für die foreach-Schleife bereit. Nachdem der Aufrufer diesen Wert verarbeitet hat, fährt der Iterator mit der nächsten Eingabe fort.
Verwenden Sie das generische IEnumerable<T>-Formular für die meisten modernen C#-Codes. Das Typargument, z. B. int, teilt Aufrufern mit, welchen Elementtyp die Sequenz enthält.
Beenden Sie die Sequenz mit yield break
Verwenden Sie yield break, um einen Iterator zu beenden, bevor die Ausführung das Ende der Methode erreicht. Im Beispiel bedeutet der Sentinelwert -1 , dass keine weiteren Lesewerte verfügbar sind:
if (reading == -1)
{
yield break;
}
Der Iterator endet außerdem automatisch, sobald die Ausführung das Ende seines Hauptteils erreicht. Verwenden Sie yield break, wenn eine Bedingung die Elementproduktion sofort beenden soll.
Einen Iterator mit foreach verarbeiten
Ein Iterator hat dieselbe IEnumerable<T>-Struktur wie viele .NET-Sammlungen. Aufrufer können foreach verwenden, ohne zu wissen, wie die Sequenz ihre Elemente erzeugt:
foreach (int temperature in SelectTemperatures(readings, 25))
{
Console.WriteLine($"Accepted: {temperature}°C");
}
Der Aufrufer fordert jedes Element an, während die Schleife voranschreitet. Der Iterator behält seine Position zwischen Anfragen bei und setzt nach dem vorherigen yield return fort.
Die verzögerte Elementerzeugung verstehen
Das Aufrufen einer Iteratormethode führt ihren Codeblock nicht sofort aus. Die Methode beginnt, Elemente zu erzeugen, wenn der Aufrufer mit der Enumeration beginnt. Dieses Verhalten wird als verzögerte Ausführung bezeichnet.
Das Beispiel gibt Sequence created. vor allen Checking ...-Nachrichten aus. Der Iterator startet die Überprüfung der Lesewerte nur, wenn die foreach Schleife ihr erstes Element anfordert.
Verzögerte Ausführung hat praktische Auswirkungen:
- Der Aufrufer kann mit der Verarbeitung beginnen, bevor der Iterator jedes Element erzeugt.
- Der Iterator kann mit
yield breakvorzeitig stoppen. - Ein Aufrufer, der die Sequenz nie durchläuft, führt den Iterator-Körper nicht aus.
- Jede neue Enumeration durchläuft den Iterator erneut.
Machen Sie die verzögerte Ausführung in der Beschreibung und Dokumentation der Methode deutlich. Leser können den Ausführungszeitpunkt nicht allein aus IEnumerable<T> ableiten, da sowohl Iteratoren als auch Sammlungen diese Schnittstelle verfügbar machen können. Halten Sie die Elementproduktion frei von nicht verwandten Nebenwirkungen, da Aufrufer die Sequenz später oder mehr als einmal durchlaufen können. Die Diagnosemeldungen des Beispiels veranschaulichen diesen zeitlichen Ablauf.
Iterator oder Sammlung auswählen
Gibt einen Iterator zurück, wenn Werte auf natürliche Weise einzeln eingehen oder wenn der Aufrufer das vollständige Ergebnis nicht sofort benötigt. Eine vollständige Sammlung zurückgeben, wenn Aufrufer eine stabile Momentaufnahme, einen indizierten Zugriff oder eine wiederholte Aufzählung benötigen, ohne die Elemente neu zu berechnen.
Beide Ansätze können dieselben Elemente zurückgeben. Der Iterator überlässt die Elementerzeugung der Kontrolle des Aufrufers; eine Methode, die eine Auflistung erstellt, schließt diese Arbeit ab, bevor sie zurückgegeben wird.
Verwenden Sie eine normale Schleife, wenn Sie eine Aktion für jedes Element ausführen möchten, ohne eine Sequenz zurückzugeben. Für einen Standardfilter oder eine Standardtransformation verwenden Sie vorzugsweise einen LINQ-Vorgang wie Where oder Select; schreiben Sie einen Iterator, wenn benutzerdefinierte Logik zur Erzeugung von Elementen als eine Reihe von Anweisungen klarer ist.
Iteratormethoden lassen sich mit LINQ kombinieren, da beide IEnumerable<T> verwenden. Beispielsweise kann ein Anrufer einen weiteren Filter hinzufügen:
var comfortableReadings = SelectTemperatures(readings, 25)
.Where(static temperature => temperature >= 18);
Der Iterator- und LINQ-Vorgang bleibt zurückgestellt, bis der Code comfortableReadings enumeriert.
Informationen zu asynchronen Sequenzen finden Sie unter Generieren und Nutzen asynchroner Datenströme. Verwenden Sie für benutzerdefinierte Enumerationsmuster und alle yield Einschränkungen die Sprachreferenz.