Background
Iterators have become an important part of programming languages with the advent of collections that need to be iterated over. In Visual Basic, support for IEnumerable/IEnumerator has been available since the .NET version, allowing the implementation of custom enumerable collections and using the For Each loop for convenient and concise access to the contents of collections.
Problem
Many developers limit themselves to using only built-in collections or do not correctly implement the IEnumerable interface, resulting in the inability to iterate over objects using For Each. Additionally, implementing and maintaining the state of the iterator through Current and MoveNext can be challenging.
Solution
To support iterations, the type implements the IEnumerable interface (or the generic IEnumerable(Of T)). Implement the GetEnumerator function, returning an object that implements IEnumerator. In VB.NET, iterator methods with the Yield keyword can also be used (starting from VB 2015), which greatly simplifies the implementation of iteration.
Example code:
Imports System.Collections Public Class SimpleCollection Implements IEnumerable Private arr() As Integer = {1, 2, 3} Public Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator For Each i In arr Yield i ' for VB 2015+ Next End Function End Class ' Usage: For Each n As Integer In New SimpleCollection() Console.WriteLine(n) Next
Key features:
Is it mandatory to implement both interfaces: IEnumerable and IEnumerator, to support For Each?
No, it is sufficient to implement IEnumerable and return a compatible iterator. If you want to implement iteration, you can use an existing IEnumerator from an inner collection. However, for full customization, both parts need to be implemented.
Example code:
Public Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator Return arr.GetEnumerator() ' using the built-in array iterator End Function
Can IEnumerable be implemented only explicitly (Explicit Interface Implementation) in Visual Basic?
Yes, you can implement the interface explicitly, especially when your collection already has its own GetEnumerator and you want to hide the interface implementation. Such a GetEnumerator cannot be called directly, but For Each will work.
Example code:
Public Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator ' ...method body End Function
What happens if GetEnumerator returns Nothing?
An exception will be thrown at the first attempt to iterate over the collection, as For Each expects a valid iterator.
The collection class did not implement IEnumerable, and a separate Next method was created for iterating over elements. As a result, it cannot be used in generic methods or For Each, requiring additional method implementations.
Pros:
Cons:
The developer implemented IEnumerable and GetEnumerator, the collection now works with For Each and integrates with LINQ.
Pros:
Cons: