Christian S. hat folgendes geschrieben: |
"Merkt" sich der Compiler dann, dass er beim dritten Element die ersten zwei yield-return-Anweisungen ignorieren muss? |
Hihi, nö. ... Naja so ähnlich jedenfalls...
Wenn du in einer Methode yield benutzt wird der Compiler eine private nested class anlegen, die selbst IEnumerable[meta]wenn du IEnumerable<T> als rückgabewert hast auch IEnumerable<T>[/meta] implementiert und im Konstruktor die Parameter deiner Methode bekommt.
Jedes yield innerhalb deines Iterators entspricht nachher einem Wert den der ,ebenfalls angelegte, Enumerator zurückgibt.
Ist das Ende deiner Methode erreicht wird MoveNext des Enumerators false liefern.
Auf die Art kann man zum Beispiel direkt durch Dateien iterieren
ohne die einzelnen Objekte erst in einen Container werfen zu müssen.
Du musst also immer nur ein Objekt im Speicher halten.
Der code deiner Methode wird in die iterator Klasse kopiert und etwas umgebaut. Alle Bezüge auf this/self werden auf ein Feld des iterators umgebogen. Außerdem darfst du leider keine using statements innerhalb des Iterators nehmen... :-/
Hier ein kleiner Bleistift um eine CSV zu durchlaufen:
Pascal:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| class method ConsoleApp.ReadPersonsFrom(reader : StreamReader) : IEnumerable<Person>; begin while reader.Peek() <> -1 do begin var splittedLine := reader.ReadLine().Split([';']);
var person := new Person(splittedLine[0], splittedLine[1], Integer.Parse(splittedLine[2])); yield (person); end; end;
class method ConsoleApp.Main; begin using reader := new StreamReader('Persons.txt', Encoding.Default) do for person : Person in ReadPersonsFrom(reader) do Console.WriteLine('{0}, {1} ({2})', Person.Name, Person.FirstName, Person.Age); end; |
C# port:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23:
| static IEnumerable<Person> ReadPersonsFrom(StreamReader reader) { while (reader.Peek() != -1) { string[] splittedLine = reader.ReadLine().Split(new char[1] {';'});
Person person = new Person(splittedLine[0], splittedLine[1], int.Parse(splittedLine[2])); yield return person; } }
static void Main(string[] args) { using (StreamReader reader = new StreamReader("Persons.txt", Encoding.Default)) foreach (Person person in ReadPersonsFrom(reader)) Console.WriteLine("{0}, {1} ({2})", person.Name, person.FirstName, person.Age);
} |
btw: Iteratoren verwendet man eigentlich nicht in GetEnumerator...
Nein, man kann leider keinen Iterator in einen XmlSerializer werfen...