Click here to Skip to main content
15,886,362 members
Articles / Programming Languages / Visual Basic

Implementation of IEnumerable(of T) & IEnumerator(Of T) in VB.NET

Rate me:
Please Sign up or sign in to vote.
3.47/5 (8 votes)
21 Jul 2011CPOL4 min read 58.7K   725   17   5
Read the data in the Collection

Introduction

This article demonstrates how to implement both IEnumerable(Of T) and IEnumerator(Of T) in VB.NET and use them to read data in a collection.

Background

How can I do iteration over a collection? ....... for VB coders, almost the question has no answer, and if you search over the internet you might be lucky to find enough information which may answer such a question. C# coders are really lucky with Yield statement and VB.NET coders must suffer a little .....

What I Shall Implement?

Actually, there is a time when you may need to build your own iterator, such a case may occur when you need to read data from a certain collection, and to build your own Iterator in VB.NET you must implement both IEnumerator(Of T) and IEnumerable(Of T) either in one single class or in two separate classes. Also you must implement the methods and properties related to both IEnumerable(Of T) & IEnumerator(Of T) interfaces. The methods and properties which shall be implemented for each interface are listed below.

IEnumerable(Of T) Methods

Since IEnumerable(Of T) is inherited from IEnumerable interface, you will have to implement two similar Functions that are almost identical in names, but they are differ in the return type.

Name Description Interface Return Type
GetEnumerator Function IEnumerable(Of T) Generic
GetEnumerator1 Function IEnumerable Non Generic

Which function shall be implemented? Always you shall implement the strongly typed generic function and be sure to change the non-generic function to Private and call the generic method inside it, if required to access the private method by any means, you may just cast through the interface.

VB.NET
Public FunctionGetEnumerator() As System.Collections.Generic.IEnumerator(
    Of T) ImplementsSystem.Collections.Generic.IEnumerable(Of T).GetEnumerator
' Add implementation here
End Function
 Private FunctionGetEnumerator1() _
 As System.Collections.IEnumerator ImplementsSystem.Collections.IEnumerable.GetEnumerator
' Just call the generic Function
 ReturnGetEnumerator()
End Function

IEnumerator(Of T) Methods & Properties

Also, since IEnumerator(of T) is inherited from both IDisposable & IEnumerator interfaces, then you will have to implement two identical read only properties that almost have the same names, but differ in the return type, the one with generic return type comes from IEnumerable(Of T) and the other one with non-generic return type comes from IEnumerable plus two methods with non-generic return type comes from IEnumerable interface. In addition to that, you will have to implement the methods related to IDisposable interface.

Name Description Interface Return Type
Current ReadOnly Property IEnumerable(Of T) Generic
Current1 ReadOnly Property IEnumerable Non Generic
MoveNext Method IEnumerable Non Generic
Reset Method IEnumerable Non Generic

Which property shall be implemented? As we did above with GetEnumerator, you shall implement the strongly typed generic property and be sure to change the non-generic property to Private and return the generic property inside it.

VB
Public ReadOnly Property Current As T _
	Implements System.Collections.Generic.IEnumerator(Of T).Current
Get
' Add implementation here
End Get
End Property
Private ReadOnly Property Current1 As Object _
	ImplementsSystem.Collections.IEnumerator.Current
Get
' Just return the generic property value
Return Me.Current
End Get
End Property
Public FunctionMoveNext() As BooleanImplements System.Collections.IEnumerator.MoveNext
' Add implementation here
End Function
Public Sub Reset() Implements System.Collections.IEnumerator.Reset
' Add implementation here
End Sub
' IDisposable Support goes here

IDisposable Methods & Properties

Name Description Interface Return Type
Dispose Method IDisposable Nothing
Dispose Method IDisposable Boolean

What to do with IDisposable methods? Actually nothing to be implemented here simply deletes or comments the code except the Dispose method. Just be sure to change it to Private.

VB.NET
#Region "IDisposable Support" 
 Private disposedValue As Boolean ' To detect redundant calls
'' IDisposable
'Protected Overridable Sub Dispose(ByVal disposing As Boolean)
'If Not Me.disposedValue Then
'If disposing Then
'' TODO: dispose managed state (managed objects).
'End If
'' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
'' TODO: set large fields to null.
'End If
'Me.disposedValue = True
'End Sub
' TODO: override Finalize() only if Dispose(ByVal disposing As Boolean)
' above has code to free unmanaged resources.
'Protected Overrides Sub Finalize()
'' Do not change this code.Put cleanup code in Dispose(ByVal disposing As Boolean) above.
'Dispose(False)
'MyBase.Finalize()
'End Sub
' This code added by Visual Basic to correctly implement the disposable pattern.
Private Sub Dispose()Implements IDisposable.Dispose
'' Do not change this code.Put cleanup code in Dispose(ByVal disposing As Boolean) above.
'Dispose(True)
'GC.SuppressFinalize(Me)
End Sub
#End Region

Remember: Always, you shall implement the generic methods & properties, in addition to that the nongeneric MoveNext and Reset methods.

Build Iterator

To demonstrate how to build iterator, consider you have an interface and/or a Component which implements that interface.

VB.NET
Imports System.Windows.Forms
Imports System.Drawing
Public Interface IRiverNile
Property Font() As Font
Property Text() As String
Property Description() AsString
Property Image() As Image
Property Disabled() AsBoolean
Property control As Control
End Interface
Public Class RiverNileComponent
Implements IRiverNile
' rest of code goes here
End Class
  • Consider that you want to write your own Collection for that interface or component, and your collection is inherited from Collectionsbase Class and also implements IList(Of T).
VB.NET
Public Class RiverNileCollection
Inherits Collectionsbase
Implements IList(Of IRiverNile)
' rest of the codes goes here
End Class
  • Add your nested Iterator Class, at the end of the Collection Class.
  • Define your private values in the Iterator Class, and add a constructor for the iterator.
VB.NET
Public Class RiverNeCollection
Inherits Collectionbase
Implements IList(Of IRiverNile)
' rest of the codes goes here
Private Class RiverNileCollectionEnumerator
Implements IEnumerator(Of IRiverNile)
Implements IEnumerable(Of IRiverNile)
Private _collection As RiverNileCollection
Private _index As Integer
Private _current As IRiverNile
Public Sub New(ByVal collection As RiverNileCollection)
MyBase.New()
_collection = collection
_index = -1
_current = CType(Nothing, IRiverNile)
End Sub
End Class
End Class
  • As explained before, the nongeneric function shall be changed to private and shall return the generic function value.
  • The generic function shall return the New Iterator value.
VB.NET
' rest of the codes goes here

Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(
   Of IRiverNile) Implements System.Collections.Generic.IEnumerable(
   Of IRiverNile).GetEnumerator

Return New RiverNileCollectionEnumerator(_collection)

End Function

Private Function GetEnumerator1() As System.Collections.IEnumerator _
Implements System.Collections.IEnumerable.GetEnumerator

Return GetEnumerator()

End Function

' rest of the codes goes here
  • As explained earlier, the nongeneric Current Property shall be Private and shall return the value of generic Current Property.
  • The generic Current Property then return the correspondent private, an InvalidOperationExpected shall be thrown if your value is nothing.
VB.NET
' rest of the codes goes here
Public ReadOnly Property Current As IRiverNile Implements _
	System.Collections.Generic.IEnumerator(Of IRiverNile).Current
Get
If _current Is Nothing Then
Throw New InvalidOperationException()
End If
Return _current
End Get
End Property
Private ReadOnly Property Current1 As Object Implements _
	System.Collections.IEnumerator.Current
Get
Return Me.Current
End Get
End Property
' rest of the codes goes here
  • Implement the nongeneric MoveNext and Reset Methods.
  • The MoveNext Method shall return False to avoid going beyond the end of the collection when the index is equal to the collection Count Property, else will return True and then you set the current value
VB.NET
' rest of the codes goes here
Public Function MoveNext() As Boolean Implements System.Collections.IEnumerator.MoveNext
If _index = _collection.Count Then
' Avoids going beyond the end of the collection.
Return False
Else
'Set current box to next item in collection.
_current = _collection(_index)
End If
Return True
End Function
Public Sub Reset() Implements System.Collections.IEnumerator.Reset
_index = -1
_current = CType(Nothing, IRiverNile)
End Sub
  • Once you complete your iterator, return a New Value of it in the Collection Class GetEnumerator Method.
VB.NET
' Rest of code goes here

Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(
    Of IRiverNile) Implements System.Collections.Generic.IEnumerable(
    Of IRiverNile).GetEnumerator

Return New RiverNileCollectionEnumerator(Me)

End Function

' Rest of code goes here

Generics Iterator

The problem with the above iterator is that you may have to write an iterator class for any collection class, so instead of that, it is better to write a generic class that can be used with any List(Of T) or any Collection(of T) and here it is.

VB.NET
''' <summary>
''' Copyright © Omar Amin Ibrahim 2011
''' silverlight1212@yahoo.com
''' </summary>
''' <typeparam name="T"></typeparam>
''' <remarks></remarks>
Public Class RiverNileListEnumerator(Of T)
    Implements IEnumerable(Of T)
    Implements IEnumerator(Of T)

#Region " Fields "
     Private _list As IList(Of T)
    Private _index As Integer
    Private _current As T

#End Region

#Region " Constructor "
     Public Sub New(ByVal list As IList(Of T))
        MyBase.New()
        _list = list
        _index = -1
        _current = CType(Nothing, T)
    End Sub

#End Region

#Region " Properties "
     Public ReadOnly Property Current As T _
	Implements System.Collections.Generic.IEnumerator(Of T).Current
        Get
            If _current Is Nothing Then
                Throw New InvalidOperationException()
            End If

            Return _current
        End Get
    End Property

    Private ReadOnly Property System_Collections_Current As _
	Object Implements System.Collections.IEnumerator.Current
        Get
            Return Me.Current
        End Get
    End Property

#End Region

#Region " Methods "
     Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of T) _
	Implements System.Collections.Generic.IEnumerable(Of T).GetEnumerator
        Return New RiverNileListEnumerator(Of T)(Me._list)
    End Function

    Private Function System_Collections_GetEnumerator() _
	As System.Collections.IEnumerator_
	 Implements System.Collections.IEnumerable.GetEnumerator
        Return Me.GetEnumerator
    End Function

    Public Function MoveNext() As Boolean Implements _
	System.Collections.IEnumerator.MoveNext
        _index = _index + 1
        If _index = _list.Count Then
            Return False
        Else
            _current = _list(_index)
        End If
        Return True
    End Function

    Public Sub Reset() Implements System.Collections.IEnumerator.Reset
        _index = -1
        _current = CType(Nothing, T)
    End Sub

    Private Sub System_IDisposable_Dispose() Implements IDisposable.Dispose
        ' do nothing
    End Sub

#End Region

End Class ' RiverNileListEnumerator

Implementation with Collection

VB.NET
''' <summary>
''' Copyright © Omar Amin Ibrahim 2011
''' silverlight1212@yahoo.com
''' </summary>
''' <typeparam name="T"></typeparam>
''' <remarks></remarks>
Public Class RiverNileCollectionEnumerator(Of T)

    Implements IEnumerable(Of T)
    Implements IEnumerator(Of T)

#Region " Fields "
     Private _collectiont As ICollection(Of T)
    Private _index As Integer
    Private _current As T

#End Region

#Region " Constructor "
     Public Sub New(ByVal collection As ICollection(Of T))
        MyBase.New()
        _collectiont = collection
        _index = -1
        _current = CType(Nothing, T)
    End Sub

#End Region

#Region " Properties "
     Public ReadOnly Property Current As T
        Get
            If _current Is Nothing Then
                Throw New InvalidOperationException()
            End If

            Return _current
        End Get
    End Property

    Private ReadOnly Property System_Collections_Generic_Current _
	As T Implements System.Collections.Generic.IEnumerator(Of T).Current
        Get
            Return Me.Current
        End Get
    End Property

    Private ReadOnly Property System_Collections_Current _
	As Object Implements System.Collections.IEnumerator.Current
        Get
            Return Me.Current
        End Get
    End Property

#End Region

#Region " Methods "
     Public Function GetEnumerator() As IEnumerator(Of T)
        Return New RiverNileCollectionEnumerator(Of T)(Me._collectiont)
    End Function

    Public Function MoveNext() As Boolean
        _index = _index + 1
        If _index = _collectiont.Count Then
            Return False
        Else
            _current = _collectiont(_index)
        End If
        Return True
    End Function

    Public Sub Reset()
        _index = -1
        _current = CType(Nothing, T)
    End Sub

    Private Function System_Collections_Generic_GetEnumerator() _
	As System.Collections.Generic.IEnumerator(Of T) Implements _
	System.Collections.Generic.IEnumerable(Of T).GetEnumerator
        Return Me.GetEnumerator
    End Function

    Private Function System_Collections_GetEnumerator() As _
	System.Collections.IEnumerator Implements _
	System.Collections.IEnumerable.GetEnumerator
        Return Me.GetEnumerator
    End Function

    Private Function System_Collections_MoveNext() As Boolean _
	Implements System.Collections.IEnumerator.MoveNext
        Return MoveNext()
    End Function

    Private Sub System_Collections_Reset() _
	Implements System.Collections.IEnumerator.Reset
        Me.Reset()
    End Sub

    Private Sub System_IDisposable_Dispose() Implements IDisposable.Dispose
        ' do nothing
    End Sub

#End Region

End Class ' RiverNileCollectionEnumerator

Iterator

VB.NET
''' <summary>
''' Copyright © Omar Amin Ibrahim 2011
''' silverlight1212@yahoo.com
''' </summary>
''' <remarks></remarks>
Public NotInheritable Class RiverNileGenerics

    Public Shared Function Iterator(Of T)(ByVal list As IList(Of T)) _
	As RiverNileListEnumerator(Of T)
        If (list Is Nothing) Then
            Throw New ArgumentNullException("list")
        End If
        Return New RiverNileListEnumerator(Of T)(list)
    End Function

    Public Shared Function Iterator(Of T)(ByVal collection As ICollection(Of T)) _
	As RiverNileCollectionEnumerator(Of T)
        If (collection Is Nothing) Then
            Throw New ArgumentNullException("collection")
        End If
        Return New RiverNileCollectionEnumerator(Of T)(collection)
    End Function

End Class ' RiverNileGenerics

Using the Code

It is simple. Try it.

VB.NET
Imports RiverNile.RiverNileGenerics

Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, _
	ByVal e As System.EventArgs) Handles MyBase.Load

        Dim ColorCollection As ICollection(Of KnownColor) = _
	New List(Of KnownColor) From {KnownColor.Aqua, KnownColor.Red, KnownColor.Black}
        For Each clr As KnownColor In Iterator(ColorCollection)
            ListBox1.Items.Add(clr)
        Next

        Dim StringList As IList(Of String) = New List(Of String) _
				From {"Omar", "Amin", "Ibrahim"}
        For Each Str As String In Iterator(StringList)
            ListBox2.Items.Add(Str)
        Next

    End Sub

End Class

How To Use It With a Collection

  1. Define your collection.
  2. Implements IList(Of n).
  3. Just call the shared method from the RiverNileGenerics Class as below:
VB.NET
Imports RiverNile.RiverNileGenerics
Public Class BarCollection
    Inherits CollectionBase
    Implements IList(Of Bar)

#Region " Fields "
     Private owner As BarControl

#End Region

#Region " Constructor "
     Public Sub New(ByVal containerControl As BarControl)
        Me.owner = containerControl
    End Sub

#End Region

#Region " Methods "
     Public Overloads Function GetEnumerator() As IEnumerator(Of Bar)
        Return Iterator(Of Bar)(Me)
    End Function

    Private Function System_Collections_Generic_GetEnumerator() _
	As System.Collections.Generic.IEnumerator(Of Bar) _
	Implements System.Collections.Generic.IEnumerable(Of Bar).GetEnumerator
        Return Me.GetEnumerator
    End Function

    ' rest of the codes goes here

#End Region

End Class

References

History

  • 10th July, 2011: First release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Engineer
Egypt Egypt
Oil & Gas Engineer
C# & VB.net
Coding For Fun Only

Comments and Discussions

 
GeneralMy vote of 5 Pin
Manoj Kumar Choubey23-Feb-12 21:47
professionalManoj Kumar Choubey23-Feb-12 21:47 
General[My vote of 1] Not much to learn from this article Pin
pinx26-Jul-11 2:59
pinx26-Jul-11 2:59 
GeneralMy vote of 2 Pin
Gregory Gadow12-Jul-11 3:12
Gregory Gadow12-Jul-11 3:12 
QuestionAm I missing something but could I not just use Pin
Sacha Barber10-Jul-11 21:54
Sacha Barber10-Jul-11 21:54 
AnswerRe: Am I missing something but could I not just use Pin
a_pess11-Jul-11 2:20
a_pess11-Jul-11 2:20 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.