1. 13
Collection Objects
Earlier we used an array in a foreach. If the array had three members, the foreach got executed
three times and each time the variable i had a different value. The concept described below is
called a collection class. It is a class that returns a value each time till the values run out, thus
making it easier for us to iterate through the array.
a.cs
public class zzz
{
public static void Main()
{
yyy f = new yyy();
foreach (string i in f)
{
}
}
}
class yyy
{
}
Compiler Error
a.cs(6,1): error CS1579: foreach statement cannot operate on variables of type âyyyâ
because âyyyâ does not contain a definition for âGetEnumeratorâ, or it is inaccessible
To use yyy in a foreach as a collection class, foreach requires a function GetEnumerator.
a.cs
public class zzz
{
public static void Main()
{
yyy f = new yyy();
foreach (string i in f)
{
}
}
}
class yyy
2. {
public int GetEnumerator()
{
}
}
Compiler Error
a.cs(6,1): error CS1579: foreach statement cannot operate on variables of type 'yyy'
because 'int' does not contain a definition for 'MoveNext', or it is inaccessible
a.cs(13,12): error CS0161: 'yyy.GetEnumerator()': not all code paths return a value
Foreach obviously tries to execute the function called GetEnumerator. This function should not
return an int but something else as the error suggests.
a.cs
using System.Collections;
public class zzz
{
public static void Main()
{
yyy f = new yyy();
foreach (string i in f)
{
}
}
}
class yyy
{
public IEnumerator GetEnumerator()
{
return new xxx();
}
}
class xxx : IEnumerator
{
}
Compiler Error
a.cs(19,7): error CS0535: âxxxâ does not implement interface member
âSystem.Collections.IEnumerator.MoveNext()â
a.cs(19,7): error CS0535: âxxxâ does not implement interface member
âSystem.Collections.IEnumerator.Reset()â
a.cs(19,7): error CS0535: âxxxâ does not implement interface member
âSystem.Collections.IEnumerator.Currentâ
IEnumerator is an interface which has three functions MoveNext, Reset and Current and xxx has
to implement all of them to remove the compiler errors.
a.cs
using System.Collections;
3. public class zzz
{
public static void Main()
{
yyy f = new yyy();
foreach (string i in f)
{
System.Console.WriteLine(i);
}
}
}
class yyy
{
public IEnumerator GetEnumerator()
{
return new xxx();
}
}
class xxx : IEnumerator
{
public bool MoveNext()
{
System.Console.WriteLine(âMoveNextâ);
return true;
}
public void Reset()
{
System.Console.WriteLine(âResetâ);
}
public object Current
{
get
{
System.Console.WriteLine(âCurrentâ);
return âhiâ;
}
}
}
Run the program and you will notice that the output does not stop. It goes on forever.
IEnumerator is an interface which belongs to the namespace System.Collections. foreach first
calls the function GetEnumerator from yyy. It expects this function to return an object like
IEnumerator. It then calls the function MoveNext from this returned object. If MoveNext returns
true it knows that there is some data to be read and it calls the property Current to access this
data. From Current the get accessor gets called which always returns âhiâ in our case. Then
MoveNext gets called and if it returns false, we quit out of the foreach statement. As MoveNext
always returns true, we go into an indefinite loop.
a.cs
using System.Collections;
public class zzz
{
public static void Main()
4. {
yyy f = new yyy();
foreach (string i in f)
{
System.Console.WriteLine(i);
}
}
}
class yyy
{
public IEnumerator GetEnumerator()
{
return new xxx();
}
}
class xxx : IEnumerator
{
public string [] a = new string[3] {âhiâ , âbyeâ ,ânoâ};
public int i = -1;
public bool MoveNext()
{
i++;
System.Console.WriteLine(âMoveNextâ + i);
if ( i == 3)
return false;
else
return true;
}
public void Reset()
{
System.Console.WriteLine(âResetâ);
}
public object Current
{
get
{
System.Console.WriteLine(âCurrent â + a[i]);
return a[i];
}
}
}
Output
MoveNext0
Current hi
hi
MoveNext1
Current bye
bye
MoveNext2
Current no
no
MoveNext3
5. We have created an array a which has 3 members and initialized them respectively to hi, bye and
no by giving the strings in {} immediately after the new. Each time MoveNext gets called the
variable i is increased by 1. If the value of i is 3, we have no more strings to return and thus we
return false, else we return true. The variable i keeps track of how many times the function
MoveNext is being called. As MoveNext returns true, Current gets called which returns a string
from the array using i as the offset. Thus we can iterate through the entire array depending upon
the length.
a.cs
using System.Collections;
public class zzz
{
public static void Main()
{
yyy f = new yyy(âThis is Greatâ);
foreach (string i in f)
{
System.Console.WriteLine(i);
}
}
}
class yyy
{
string t;
public yyy(string t1)
{
t = t1;
}
public IEnumerator GetEnumerator()
{
return new xxx(t);
}
}
class xxx : IEnumerator
{
public string [] a;
public xxx(string t3)
{
char [] b = new char[1];
b[0] = â â;
a = t3.Split(b);
}
public int i = -1;
public bool MoveNext()
{
i++;
System.Console.WriteLine(âMoveNext â + i);
if ( i == a.Length)
return false;
else
return true;
}
public void Reset()
6. {
System.Console.WriteLine(âResetâ);
}
public object Current
{
get
{
System.Console.WriteLine(âCurrent â + a[i]);
return a[i];
}
}
}
Output
MoveNext 0
Current This
This
MoveNext 1
Current is
is
MoveNext 2
Current Great
Great
MoveNext 3
Pretty big program. At the time of creating a yyy object we are passing a string to the
constructor. Thus the yyy constructor gets called first. The constructor stores this string in
variable t. The foreach statement calls GetEnumerator which now creates a xxx object
passing it the string through t. The constructor of xxx now gets called. Every string class
has a member function called Split. Split will break up a string on certain characters
which we call delimiters. In this case, we want our string to be broken up whenever we
encounter a space. The Split function requires an array of chars which it can use as a
delimiter. The reason it requires an array is because we may have more than one char that
we would like to break the string on. Like earlier, the array a now contains the array of
strings. The last change is the condition in the if statement. Earlier we used a constant
number, now we use a member, Length, of an array which stores the length of the array
or the number of members. Thus the class yyy can now be used as a collection class
which enumerates the individual words in the string. The function Reset for some reason
never ever gets called.