IEnumerable and IEnumerator

.NET has a range of keywords that execute iteration over an enumerator of some kind. These are just structures that like an iterator that support passing out a collection of objects one at a time. For example an int[] type is compatible and words as an enumerator passing one value at a time time foreach procedure to be output.

int[] arr = {1, 1, 2, 3, 5}
foreach(int i in arr)
{
  Console.WriteLine(i); // => 1, 1, 2, 3, 5
}

IEnumerable

You can define your own iteratble structures in C# using the IEnumerable and IEnumerator interfaces. Sometimes you can do this by implementing an enumerator directly on your class with a custom iteration schema, but often you will just want to use IEnumerable as access for a private iterable property of your class.

This is useful because it allows you to directly use iteration on an instance of class and define a custom interface for how that interation takes place.

// NotEnumerable.cs
public class NotEnumerable
{
  public int[] arr { get; }
  public NotEnumerable()
  {
    arr = int[] {1, 2, 3, 4, 5}
  }
}

Otherwise you have to access the enumerable object within a class and iterate over that instead.

// Program.cs
var ne = new NotEnumerable();
foreach(int i in ne.arr)
{
  // do something with contents of arr
}

The IEnumerable interface is used to define a structure that supports enumeration with IEnumerator. The IEnumerable interface contains a single method signature GetEnumerator that returns an IEnumerator which contains the methods that actually support enumeration. This the method that enumeration procedures like foreach check for, before iterating through a collection.

public interface IEnumerable
{
  IEnumerator GetEnumerator();
}

To implement IEnumerable on a class you can return the enumerable result of GetEnumerator on the enumerable structure within the class when implementing the IEnumerable interface.

public class IsEnumerable : IEnumerable
{
  private int[] arr;
  public IsEnumerable()
  {
    arr = int[] {1, 2, 3, 4, 5}
  }
  public IEnumerator GetEnumerator()
  {
    return arr.GetEnumerator();
  }
}

Now, when you use your class that implements IEnumerable with a foreach or other iterator procedure it will return the enumeration for a structure within the class AND the internal collection can remain private, as in the example above.

For classes that implement IEnumerator within a custom enumeration you can use IEnumerable to return itself cast to IEnumerator which will give the iteration procedure calling it access to the custom defined enumeration methods.

// NOT RECOMMENDED
public class MyEnumerator : IEnumerable, IEnumerator
{
  // -- implementation for custom enumerator here --
  public IEnumerator GetEnumerator()
  {
    // cast this to IEnumerator and return it
    return (IEnumerator) this;
  }
}

This is, however, not recommended, you should separate your IEnumerable and IEnumerator classes and ideally createa a new instance of the IEnumerator whenever enumeration is required. The example below shows an IEnumerable implementation that just returns a new hardcoded array of data, however, this could be dynamic using custom IEnumerators, the important thing is that it creates a new instance to return to any iterators.

public class MyEnumerable : IEnumerable
{
  public IEnumerator GetEnumerator()
  {
    return new int[] {1, 2, 3, 4, 5};
  }
}

IEnumerator

You can define your own enumerators using the IEnumerator interface. The signature for this interface uses two methods, MoveNext and Reset, and a property called Current.

public interface IEnumerator
{
  public bool MoveNext();
  public void Reset();
  public object Current; 
}

The MoveNext method changes a variable that keeps track of the index of enumeration and indicates when enumeration is finished by returning false. The MoveNext method runs before a value is retrieved during iteration therefore, whatever values MoveNext changes needs to be out of range before starting. In the example below the position variable keeps track of where iteration is and is initialized at -1 so that when MoveNext is called the first time before a retrieval it is at 0 ready to retrieve some information from the collection. The MoveNext method also returns true until the position is equal to the Length of the data collection at which point iteration ends.

int position = -1;
public bool MoveNext()
{
  position++;
  return (position < collection.Length);
}

The Reset method can describe a procedure for reseting the positional index for iteration, however, its not recommended to use it and is essential a holdover from interoperability into other language aspects. Indeed it is now required in the language spec for iterator blocks to throw an exception on Reset making the method essentially redundant. Below is a quick implementation for completeness sake.

public void Reset()
{
  position = -1;
}

The Current property returns an object. This is only ever an object type and is cast into the used type when the enumerator is consumed, for example the int specify in the foreach(int i in arr) makes this cast. The Current property then needs a get accessor which returns a value contained in the enumerator based on the current position.

public object Current
{
  get
  {
    return _values[position]
  }
}

You can also write the Current accessor as a lambda as with any other get property.

public object Current => _values[position]

IEnumerable<T>

A generic enumerable is an object that implements that IEnumerable and IEnumerate interface while also containing a specific type. For example an IEnumerable<string> will be an enumerable structure that returns strings as each item during iteration.