Benutzerdefinierte Enumerables
Implementieren Sie IEnumerable mit Iteratoren.
Benutzerdefinierte Enumerables ist eine kostenlose C# Academy-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des C# Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der C# Academy-Kurs umfasst insgesamt 4 Lektionen.
Eigenes Enumerable erstellen
Indem Sie IEnumerable<T> in einer Klasse implementieren, können Sie diese in einer foreach-Schleife verwenden. In Verbindung mit Iteratormethoden können Sie so mit sehr wenig Code benutzerdefinierte Collections und Wertebereiche erstellen.
GetEnumerator mit yield implementieren
Die einfachste Möglichkeit, IEnumerable<T> zu implementieren, besteht darin, GetEnumerator als Iterator mit yield return zu schreiben. Der Compiler erstellt den Enumerator für Sie.
using System;
using System.Collections;
using System.Collections.Generic;
public class IntRange : IEnumerable<int>
{
private readonly int _start, _count;
public IntRange(int start, int count) { _start = start; _count = count; }
public IEnumerator<int> GetEnumerator()
{
for (int i = 0; i < _count; i++)
yield return _start + i;
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
public class Program
{
public static void Main()
{
foreach (var n in new IntRange(5, 4))
Console.WriteLine(n);
}
}Warum gibt es zwei GetEnumerator-Methoden?
IEnumerable<T> erbt von IEnumerable ohne Generics, daher müssen Sie beide implementieren. Die explizite nicht generische Implementierung delegiert einfach an die generische Version.
using System;
using System.Collections;
using System.Collections.Generic;
public class Letters : IEnumerable<char>
{
public IEnumerator<char> GetEnumerator()
{
yield return 'x';
yield return 'y';
yield return 'z';
}
// Required because IEnumerable<T> extends IEnumerable
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
public class Program
{
public static void Main()
{
foreach (var c in new Letters())
Console.WriteLine(c);
}
}Benutzerdefinierte Logik kapseln
Ein benutzerdefiniertes Enumerable kann komplexe Erzeugungsregeln hinter einem übersichtlichen Typ verbergen. Hier gibt eine Klasse eine Fibonacci-Folge mit einer festgelegten Länge zurück.
using System;
using System.Collections;
using System.Collections.Generic;
public class Fibonacci : IEnumerable<int>
{
private readonly int _count;
public Fibonacci(int count) { _count = count; }
public IEnumerator<int> GetEnumerator()
{
int a = 0, b = 1;
for (int i = 0; i < _count; i++)
{
yield return a;
int next = a + b; a = b; b = next;
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
public class Program
{
public static void Main()
{
foreach (var n in new Fibonacci(8))
Console.WriteLine(n);
}
}Eine interne Collection umschließen
Ein benutzerdefiniertes Enumerable umschließt häufig einen internen Speicher und ermöglicht die Iteration, während es gleichzeitig kontrolliert, wie Elemente hinzugefügt oder gefiltert werden.
using System;
using System.Collections;
using System.Collections.Generic;
public class EvenBag : IEnumerable<int>
{
private readonly List<int> _items = new List<int>();
public void Add(int n) { if (n % 2 == 0) _items.Add(n); }
public IEnumerator<int> GetEnumerator() => _items.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
public class Program
{
public static void Main()
{
var bag = new EvenBag();
bag.Add(1); bag.Add(2); bag.Add(3); bag.Add(4);
foreach (var n in bag) Console.WriteLine(n);
}
}Benutzerdefinierte Enumerables funktionieren mit LINQ
Jeder Typ, der IEnumerable<T> implementiert, erhält sofort den gesamten Funktionsumfang von LINQ. Ihre benutzerdefinierte Collection kann ohne zusätzlichen Aufwand gefiltert, projiziert und aggregiert werden.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public class IntRange : IEnumerable<int>
{
private readonly int _start, _count;
public IntRange(int start, int count) { _start = start; _count = count; }
public IEnumerator<int> GetEnumerator()
{
for (int i = 0; i < _count; i++) yield return _start + i;
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
public class Program
{
public static void Main()
{
var range = new IntRange(1, 10);
Console.WriteLine(range.Where(n => n % 3 == 0).Sum());
}
}Jeder foreach erhält einen neuen Enumerator
Da GetEnumerator bei jeder Iteration aufgerufen wird, kann ein benutzerdefiniertes Enumerable wiederholt enumeriert werden. Jeder Durchlauf beginnt mit einem neuen Enumerator.
using System;
using System.Collections;
using System.Collections.Generic;
public class IntRange : IEnumerable<int>
{
private readonly int _count;
public IntRange(int count) { _count = count; }
public IEnumerator<int> GetEnumerator()
{
for (int i = 1; i <= _count; i++) yield return i;
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
public class Program
{
public static void Main()
{
var r = new IntRange(3);
foreach (var n in r) Console.Write(n);
Console.WriteLine();
foreach (var n in r) Console.Write(n); // fresh again
Console.WriteLine();
}
}Generisches benutzerdefiniertes Enumerable
Gestalten Sie das Enumerable generisch, damit es Elemente jedes beliebigen Typs aufnehmen kann. Hier stellt ein einfacher Ring seine Elemente ausgehend von einem gewählten Offset in der richtigen Reihenfolge bereit.
using System;
using System.Collections;
using System.Collections.Generic;
public class Ring<T> : IEnumerable<T>
{
private readonly T[] _items;
private readonly int _start;
public Ring(T[] items, int start) { _items = items; _start = start; }
public IEnumerator<T> GetEnumerator()
{
for (int i = 0; i < _items.Length; i++)
yield return _items[(_start + i) % _items.Length];
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
public class Program
{
public static void Main()
{
var ring = new Ring<string>(new[] { "a", "b", "c", "d" }, 2);
foreach (var s in ring) Console.WriteLine(s);
}
}Lazy-Enumerables
Da GetEnumerator selbst ein Iterator ist, ist Ihr benutzerdefiniertes Enumerable standardmäßig verzögert: Elemente werden erst erzeugt, wenn der Consumer sie abruft.
using System;
using System.Collections;
using System.Collections.Generic;
public class Squares : IEnumerable<int>
{
private readonly int _count;
public Squares(int count) { _count = count; }
public IEnumerator<int> GetEnumerator()
{
for (int i = 1; i <= _count; i++)
{
Console.WriteLine("computing " + i);
yield return i * i;
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
public class Program
{
public static void Main()
{
foreach (var n in new Squares(3))
Console.WriteLine("got " + n);
}
}Wann Sie ein benutzerdefiniertes Enumerable erstellen sollten
Verwenden Sie ein benutzerdefiniertes Enumerable, wenn die Reihenfolge der Iteration oder die Erzeugungslogik ein zentraler Bestandteil eines Typs ist, etwa bei einem Baumdurchlauf, einer seitenweise gelesenen Datenquelle oder einer mathematischen Sequenz. Andernfalls genügt eine einfache Iteratormethode.
using System;
using System.Collections;
using System.Collections.Generic;
public class Countdown : IEnumerable<int>
{
private readonly int _from;
public Countdown(int from) { _from = from; }
public IEnumerator<int> GetEnumerator()
{
for (int i = _from; i >= 0; i--) yield return i;
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
public class Program
{
public static void Main()
{
foreach (var n in new Countdown(5)) Console.WriteLine(n);
}
}Probieren Sie es selbst aus
Erstellen Sie ein benutzerdefiniertes Enumerable, das eine geometrische Folge erzeugt, und verwenden Sie anschließend LINQ darauf. Ihr Typ lässt sich direkt in das gesamte Ökosystem integrieren.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public class Geometric : IEnumerable<int>
{
private readonly int _start, _ratio, _count;
public Geometric(int start, int ratio, int count) { _start = start; _ratio = ratio; _count = count; }
public IEnumerator<int> GetEnumerator()
{
int value = _start;
for (int i = 0; i < _count; i++) { yield return value; value *= _ratio; }
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
public class Program
{
public static void Main()
{
var seq = new Geometric(1, 2, 6);
Console.WriteLine(string.Join(", ", seq));
Console.WriteLine("sum: " + seq.Sum());
}
}Kurztest
Rufen Sie sich den IEnumerable
Zusammenfassung
Ein benutzerdefiniertes Enumerable implementiert IEnumerable<T>, sodass es mit foreach und LINQ funktioniert.
- Implementieren Sie
GetEnumeratorals Iterator mityield return. - Stellen Sie außerdem die explizite nicht generische Implementierung von
GetEnumeratorbereit. - Jede Iteration erhält einen neuen Enumerator.
- Die Iteration erfolgt standardmäßig verzögert.
Häufig gestellte Fragen
Ist die Lektion „Benutzerdefinierte Enumerables“ kostenlos?
Ja — der vollständige Text von „Benutzerdefinierte Enumerables“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des C# Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der C# Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Benutzerdefinierte Enumerables“?
Implementieren Sie IEnumerable mit Iteratoren. Du übst C# Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um C# Academy zu starten?
Keine Vorkenntnisse erforderlich. C# Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.
Wie lange dauert die Lektion „Benutzerdefinierte Enumerables“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser C# Academy-Lektion Code schreiben und ausführen?
Ja. Jede C# Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Iterator-Methoden mit yield return
- yield break und vorzeitige Beendigung
- Semantik der verzögerten Auswertung
- Benutzerdefinierte Enumerables