Enumerating Objects in C#






2.41/5 (27 votes)
May 8, 2007
4 min read

81105
A tutorial on enumerating objects in C#
Introduction
Like C# provides indexers to index elements within objects, C# also provides us with Enumerators to allow us enumerate through the elements within the objects. We need to use an Interface IEnumerator
to enumerate through the elements of the object.
Seems like the technical jargon is undigestible? Let's understand what we wish to do through small examples. Consider the following example.
P1.cs
class Demo
{
public static void Main ()
{
string [] a = new string[3] {"One" , "Two" ,"Three"};
//Using the foreach loop
foreach( string s in a)
System.Console.WriteLine(s);
// Using the Enumerator Interface
System.Collections.IEnumerator en = a.GetEnumerator();
while(en.MoveNext())
System.Console.WriteLine(en.Current);
}
}
Output
One
Two
Three
One
Two
Three
The above program compiles and runs successfully to give the desired output. The above program contains an array of three strings. We print the array using foreach
loop as well as using the IEnumerator
interface.
Our goal is to have objects of a class use foreach
loop and IEnumerator
interface exacly as shown in the above program. So let's write a program to implement such a functionality step by step. Remember! Please dont compile and run the program until I say so!
We wish to have a program such that it creates an object of a class and uses it in the foreach
loop and extracts the elements of the object one by one in the following way
P2.cs
using System ;
using System.Collections ;
class Demo
{
public static void Main ()
{
Str spp = new Str();
foreach( string i in spp)
System.Console.WriteLine(i);
}
}
Ok! So in our program we have a class Str
. So the program should look like this:
P2.cs
using System ;
using System.Collections ;
class Demo
{
public static void Main ()
{
Str spp = new Str();
foreach( string i in spp)
System.Console.WriteLine(i);
}
}
class Str
{
}
We should be able to use object of class Str
in foreach
loop. The instance of our class Str
in our program is spp
. In the foreach
loop we extract every string in the instance of class spp
and print it. So it's obvious that the class should have strings as data members. Let's have class Str
hold an array of strings.
P2.cs
using System ;
using System.Collections ;
class Demo
{
public static void Main ()
{
Str spp = new Str();
foreach( string i in spp)
System.Console.WriteLine(i);
}
}
class Str
{
string [] str_arr = new string[5] {"one" , "two" ,"three", "four", "five"};
}
OK. So we have a class Str
. It contains an array of five strings. And we want to use the instance of class Str
in the foreach
loop and print the strings that belong to the instance. Our program is very much incomplete at this moment.
For our class Str
to be used in the foreach
loop we must ensure that our class implements the IEnumerable
Interface. So lets have our class Str
impliment the IEnumerable
Interface.
P2.cs
using System ;
using System.Collections ;
class Demo
{
public static void Main ()
{
Str spp = new Str();
foreach( string i in spp)
System.Console.WriteLine(i);
}
}
class Str : IEnumerable // To impliment GetEnumerator method
{
string [] str_arr = new string[5] {"one" , "two" ,"three", "four","five"};
}
IEnumerable
interface has got one public method called GetEnumerator()
. Implementing the IEnumerable
Interface means implimenting the method GetEnumerator()
. So let's go ahead an implement the method GetEnumerator
.
P2.cs
using System ;
using System.Collections ;
class Demo
{
public static void Main ()
{
Str spp = new Str();
foreach( string i in spp)
System.Console.WriteLine(i);
}
}
class Str : IEnumerable // To impliment GetEnumerator method
{
string [] str_arr = new string[5] {"one" , "two" ,"three", "four", "five"};
public IEnumerator GetEnumerator( )
{
IEnumerator r = new StrEnumerator();
return r ;
}
}
OK. We implimented the GetEnumerator
method. It returns an object that impliments interface IEnumerator
.
Now let's look at the code of the GetEnumerator
Function. Inside it we are creating an object of class StrEnumerator
and storing the reference in a reference variable of type IEnumerator
. Next the reference is returned from the function.
OK! So we need to have a class StrEnumerator
.
P2.cs
using System ;
using System.Collections ;
class Demo
{
public static void Main ()
{
Str spp = new Str();
foreach( string i in spp)
System.Console.WriteLine(i);
}
}
class Str : IEnumerable // To impliment GetEnumerator method
{
string [] str_arr = new string[5] {"one" , "two" ,"three", "four", "five"};
public IEnumerator GetEnumerator( )
{
IEnumerator r = new StrEnumerator();
return r ;
}
}
class StrEnumerator
{
}
Our class StrEnumerator
is going to help us iterate through the elements of the class Str
. So it is required that the members of our class StrEnumerator
should be able to access the private members of class Str
. So let's have class StrEnumerstor
as a nested class.
P2.cs
using System ;
using System.Collections ;
class Demo
{
public static void Main ()
{
Str spp = new Str();
foreach( string i in spp)
System.Console.WriteLine(i);
}
class Str : IEnumerable // To impliment GetEnumerator method
{
string [] str_arr = new string[5] {"one" , "two" ,"three", "four", "five"};
public IEnumerator GetEnumerator( )
{
IEnumerator r = new StrEnumerator();
return r ;
}
class StrEnumerator
{
}
}
OK! Now let's have data members for class StrEnumerator
.
P2.cs
using System ;
using System.Collections ;
class Demo
{
public static void Main ()
{
Str spp = new Str();
foreach( string i in spp)
System.Console.WriteLine(i);
}
}
class Str : IEnumerable // To impliment GetEnumerator method
{
string [] str_arr = new string[5] {"one" , "two" ,"three", "four", "five"};
public IEnumerator GetEnumerator( )
{
IEnumerator r = new StrEnumerator();
return r ;
}
class StrEnumerator
{
int index;
Str sp;
}
}
The integer index is required to keep a count of elements as we enumerate each element. sp
is a reference of type class Str
. Now let's define a constructor for class StrEnumerator
.
P2.cs
using System ;
using System.Collections ;
class Demo
{
public static void Main ()
{
Str spp = new Str();
foreach( string i in spp)
System.Console.WriteLine(i);
}
}
class Str : IEnumerable // To impliment GetEnumerator method
{
string [] str_arr = new string[5] {"one" , "two" ,"three", "four", "five"};
public IEnumerator GetEnumerator( )
{
IEnumerator r = new StrEnumerator(this);
return r ;
}
class StrEnumerator
{
int index;
Str sp;
public StrEnumerator (Str str_obj)
{
index = -1 ;
sp = str_obj ;
}
}
}
Let's say that ourObject
is an object of class Str
. We have written the constructor in such a way that the moment GetEnumerator
is executed, the constructor StrEnumerator()
is passed the reference of the object ourObject
. Data member sp
in Class StrEnumerator
now refers to the object under consideration i.e. oo.
OK. For our class Str
to be used in the foreach
loop we must ensure that our class StrEnumerator
implements the IEnumerator
Interface. Implimenting the IEnumerator
Interface means Class StrEnumerator
must define three methods: Current
, MoveNext
and Reset
.
P2.cs
using System ;
using System.Collections ;
class Demo
{
public static void Main ()
{
Str spp = new Str();
foreach( string i in spp)
System.Console.WriteLine(i);
}
}
class Str : IEnumerable // To impliment GetEnumerator method
{
string [] str_arr = new string[5] {"one" , "two" ,"three", "four", "five"};
public IEnumerator GetEnumerator( )
{
IEnumerator r = new StrEnumerator(this);
return r ;
}
class StrEnumerator
{
int index;
Str sp;
public StrEnumerator (Str str_obj)
{
index = -1 ;
sp = str_obj ;
}
public object Current
{
get
{
return sp.str_arr[ index ] ;
}
}
public bool MoveNext( )
{
if ( index < sp.str_arr.Length - 1 )
{
index++ ;
return true ;
}
return false ;
}
public void Reset( )
{
index = -1 ;
}
}
}
Ok! We are Done! Compile and Run the program. The program Compiles and runs successfully to give the following output.
one
two
three
four
five
Curent()
is invoked to read the current value. MoveNext()
is invoked to read the next value by incrementing the index count. A true is returned if the end of list is not reached. A False is returned on end of list to be returned, it returns a false. After MoveNext()
returns a False, signifyiing end of list, Reset()
is executed.