8.7 Eigene Auflistungen mit »yield« durchlaufen 

Nehmen wir an, wir hätten eine Klassendefinition wie folgt:
public class Months {
string[] months = { "Januar", "Februar", "März", "April",
"Mai", "Juni", "Juli", "August",
"September", "Oktober", "November", "Dezember"};
}
Wäre es nicht schön, mit einer foreach-Schleife den Datenspeicher des Objekts months zu durchlaufen und Zugriff auf alle Elemente zu erhalten, etwa wie folgt:
Months monate = new Months(); foreach(string temp in monate) { Console.WriteLine(temp); }
Dass daran Bedingungen geknüpft sind, wurde in Abschnitt 8.1.1, »Die elementaren Schnittstellen der Auflistungsklassen«, schon erwähnt. Die Klasse Months muss dazu die Schnittstelle IEnumerable implementieren.
public class Months : IEnumerable
Die einzige in IEnumerable definierte Methode GetEnumerator liefert ein Objekt, das wiederum die Schnittstelle IEnumerator unterstützt.
IEnumerator GetEnumerator();
Das IEnumerator-Objekt muss die Methoden MoveNext und Reset sowie die Eigenschaft Current implementieren. Damit wird das Durchlaufen der Klasse mit foreach möglich.
Die Beschreibung macht deutlich, dass einiges an Tippaufwand für die Codierung erforderlich ist. Durch den Einsatz des Schlüsselwortes yield geht es aber auch einfacher. Sie müssen zwar immer noch die Schnittstelle IEnumerable oder deren generisches Pendant und damit auch die Methode GetEnumerator implementieren, benötigen aber keinen IEnumerator-Typ mehr. Stattdessen liefern Sie die Daten nur noch mit dem neuen Schlüsselwort yield, gefolgt von return, aus.
// -------------------------------------------------------------- // Beispiel: ...\Kapitel 8\YieldSample // -------------------------------------------------------------- class Program { static void Main(string[] args) { Months months = new Months(); foreach(string temp in months) Console.WriteLine(temp); Console.ReadLine(); } } public class Months : IEnumerable { string[] month = { "Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"}; // Methode der Schnittstelle 'IEnumerable' public IEnumerator GetEnumerator() { for (int i = 0; i < month.Length; i++) yield return month[i]; } }
yield in Kombination mit return wird zur Angabe des zurückgegebenen Wertes verwendet. Bei Erreichen von yield return wird die aktuelle Position gespeichert, und beim nächsten Aufruf der Schleife wird die Ausführung von dieser Position neu gestartet. Mehr haben Sie nicht zu tun, denn im Hintergrund generiert der Compiler automatisch die Methoden Current und MoveNext der IEnumerator-Schnittstelle, wenn er yield erkennt.
Sie können das Programm sogar noch einfacher schreiben und auf die Implementierung von IEnumerable verzichten. Überlassen Sie einfach alles dem Compiler und yield return. Dazu schreiben Sie ebenfalls eine Methode, deren spezielle Aufgabe es ist, die Objektmenge zurückzuliefern. Die Methode dürfen Sie beliebig nennen. Der Rückgabewert ist ein Objekt, das die Schnittstelle IEnumerable implementiert – und somit auch implizit die Methode GetEnumerator. Hinter den Kulissen wird der Compiler dafür sorgen, dass der Iterator der anfragenden foreach-Schleife alle Daten der Reihe nach übergibt.
Das folgende Coding zeigt, wie einfach jetzt der Code ist. Beachten Sie bitte auch, dass in der foreach-Schleife nun die Methode GetList für die Bereitstellung der Objekte sorgt. In diesem Code wird die generische Schnittstelle IEnumerable<T> angegeben. Sie können natürlich auch die untypisierte benutzen, was in diesem Fall gleichwertig ist.
class Program { static void Main(string[] args) { Months months = new Months(); foreach(string temp in months.GetList()) Console.WriteLine(temp); Console.ReadLine(); } } public class Months { string[] month = { "Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"}; public IEnumerable<string> GetList() { for (int i = 0; i < month.Length; i++) yield return month[i]; } }
Weitere Möglichkeiten
yield return ist für den Compiler der Anstoß, automatisch einen Iterator zu erzeugen, der von einer foreach-Schleife genutzt werden kann. Sie können auch mehrfach hintereinander yield aufrufen, wie das folgende Codefragment zeigt:
// Methode der Schnittstelle 'IEnumerable'
public IEnumerator GetEnumerator() {
yield return "Januar";
yield return "Februar";
yield return "März";
}
Zum Abbruch einer Iteration kombinieren Sie yield mit break:
yield break;
Einschränkungen von »yield return«
Der Einsatz von yield return unterliegt zwei Einschränkungen:
- yield return kann nicht innerhalb einer anonymen Methode codiert werden.
- yield return darf weder in einem catch-Block noch in einem try-Block verwendet werden, wenn Letzterer eine catch-Klausel hat. Die Verwendung in einem try-Block, dem sich nur noch ein finally-Block anschließt, ist jedoch möglich.
In Kapitel 9, »Fehlerbehandlung und Debugging«, werden Sie alles über die Behandlung von Ausnahmen (Exceptions) mit try-catch erfahren.