However since .NET 2.0 we have a new operator called 'yield'. This allows your class to be iterated by its consumer but without the need to implement the above-mentioned interfaces.
Let us see a small example of how this works:
// Our class does not implement any interface !
public class School
{
// Explicit initialization just for demo purposes !
private string[] studentNames = {"John", "Joan",
"Joanne", "Tony", "Peter"};
// The iterating method
public IEnumerator GetEnumerator()
{
foreach (string name in studentNames)
{
// yield return in action !
yield return name;
}
}
}
And now the code for the consumer:
class Program
{
static void Main(string[] args)
{
School NorthCoast = new School();
// How School's internal collection was iterated is hidden to the user
foreach (string student in NorthCoast)
{
Console.WriteLine(student);
}
Console.ReadLine();
}
}
As you can see it is easy to make your class iteratable without having to make it implmenet any interfaces.
The following is another example (inspired by an e-mail sent to me by one of the readers of this blog!):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
MyYieldFileReader myYieldFileReader = new MyYieldFileReader();
foreach (string line in myYieldFileReader.ReadLine(@"C:\BuonVoyage.txt"))
{
Console.WriteLine(line);
}
Console.ReadLine();
}
}
class MyYieldFileReader
{
public IEnumerable ReadLine(string fileName)
{
using (StreamReader tr = new StreamReader(fileName))
{
while (!tr.EndOfStream)
{
yield return tr.ReadLine();
}
}
}
}
}
Finally, beware of the following constaints on the use of the 'yield' operator, as described in MSDN:
The yield statement can only appear inside an iterator block, which might be used as a body of a method, operator, or accessor. The body of such methods, operators, or accessors is controlled by the following restrictions:
Unsafe blocks are not allowed.
Parameters to the method, operator, or accessor cannot be ref or out.
A yield statement cannot appear in an anonymous method. For more information, see Anonymous Methods (C# Programming Guide).
When used with expression, a yield return statement cannot appear in a catch block or in a try block that has one or more catch clauses. For more information, see Exception Handling Statements (C# Reference).