Background:
The For Each...Next statement in Visual Basic allows you to iterate through elements of collections or arrays. Starting from VB6, it supported iteration over standard collections, and in VB.NET — over all types that implement a certain interface. However, when creating custom collections for your own iteration, it's important to implement the necessary infrastructure correctly.
Issue
It is not enough to implement storage for elements — the For Each statement requires support for the specialized IEnumerable interface. Often, custom collection assemblies were limited to the Add/Get methods, and the object became a "black box" for iteration. This hindered integration with the language's iteration structure and led to errors.
Solution
For For Each to work correctly with your collection, you need to implement the IEnumerable interface, and for supporting work with typed elements — IEnumerable(Of T). You also need to create your own enumerator that implements the IEnumerator interface (or IEnumerator(Of T) in generic versions).
Example:
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 ' Usage: 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
Key features:
Can you implement For Each without the IEnumerable interface, just by writing a method GetEnumerator?
No, Visual Basic requires official support for the IEnumerable/IEnumerable(Of T) interface for the compiler to recognize the collection as compatible with For Each.
Should the enumerator be a separate class?
No, if the database of elements supports the standard enumerator (for example, if you are aggregating List(Of T)), you can return its GetEnumerator. Only in complex scenarios might a custom class implementation of IEnumerator be needed.
Is it possible to modify the collection inside the For Each loop?
No, modifying the collection during iteration will lead to an InvalidOperationException. Special strategies are needed for proper handling (for example, copying the list before iteration or using indexing).
A custom class MyCollection was developed in the company with adding and removing through an array, but without implementing the IEnumerable interface. For Each did not work, and it had to use regular loops and a public field with elements.
Pros:
Cons:
The class was revamped to implement IEnumerable(Of T). After that, the collection was easily and normally used in For Each and became compatible with LINQ.
Pros:
Cons: