Geschichte der Frage:
Die Anweisung For Each...Next in Visual Basic ermöglicht es, Elemente von Sammlungen oder Arrays durchzugehen. Seit VB6 wurde der Durchlauf über Standardkollektionen unterstützt, und in VB.NET über alle Typen, die ein bestimmtes Interface implementieren. Wenn benutzerdefinierte Sammlungen für den eigenen Durchlauf erstellt werden müssen, ist es wichtig, die erforderliche Infrastruktur korrekt zu implementieren.
Problem
Es reicht nicht aus, die Speicherung von Elementen zu implementieren — For Each-Anweisungen erfordern die Unterstützung des speziellen Interfaces IEnumerable. Oft beschränkten sich die Ansammlungen benutzerdefinierter Sammlungen auf die Methoden Add/Get, das Objekt wurde zu einer "schwarzen Box" für die Iteration. Dies hinderte die Integration mit der Sprachstruktur des Durchlaufs und führte zu Fehlern.
Lösung
Damit For Each korrekt mit Ihrer Sammlung funktioniert, muss das Interface IEnumerable implementiert werden, und zur Unterstützung der Arbeit mit typisierten Elementen — IEnumerable(Of T). Es ist notwendig, einen eigenen Enumerator (Enumerator) zu erstellen, der das Interface IEnumerator (oder IEnumerator(Of T) in generischen Versionen) implementiert.
Beispiel:
Public Class IntCollection Implements IEnumerable(Of Integer) Private ReadOnly items As New List(Of Integer)() Public Sub Add(value As Integer) items.Add(value) End Sub Public Function GetEnumerator() As IEnumerator(Of Integer) _ Implements IEnumerable(Of Integer).GetEnumerator Return items.GetEnumerator() End Function Private Function IEnumerable_GetEnumerator() As IEnumerator _ Implements IEnumerable.GetEnumerator Return GetEnumerator() End Function End Class ' Verwendung: Dim col As New IntCollection() col.Add(10) col.Add(20) col.Add(30) For Each n As Integer In col Console.WriteLine(n) Next
Wichtige Merkmale:
Kann man For Each ohne das Interface IEnumerable implementieren, indem man einfach eine Methode GetEnumerator schreibt?
Nein, Visual Basic erfordert die offizielle Unterstützung des Interfaces IEnumerable/IEnumerable(Of T), damit der Compiler die Sammlung als mit For Each kompatibel erkennt.
Muss der Enumerator eine separate Klasse sein?
Nein, wenn die Elementdatenbank einen standardmäßigen Enumerator unterstützt (zum Beispiel, wenn Sie List(Of T) aggregieren), kann sein GetEnumerator zurückgegeben werden. Nur in komplexen Szenarien könnte eine eigene Implementierungsklasse IEnumerator erforderlich sein.
Ist es möglich, die Sammlung innerhalb der For Each-Schleife zu ändern?
Nein, Änderungen an der Sammlung während der Iteration führen zu einer InvalidOperationException. Für eine korrekte Verarbeitung sind spezielle Strategien erforderlich (zum Beispiel, eine Kopie der Liste vor der Iteration zu erstellen oder Indizes zu verwenden).
In einem Unternehmen wurde eine eigene Klasse MyCollection mit Hinzufügen und Entfernen über ein Array entwickelt, jedoch ohne Implementierung des Interfaces IEnumerable. For Each funktionierte nicht, es mussten normale Schleifen und ein öffentliches Feld mit Elementen verwendet werden.
Vorteile:
Nachteile:
Die Klasse wurde umgerüstet, indem IEnumerable(Of T) implementiert wurde. Danach konnte die Sammlung leicht und standardmäßig in For Each verwendet werden und war auch mit LINQ kompatibel.
Vorteile:
Nachteile: