Example of a class that Implements generic IEnumerable<T> interface
STEP1. Create MyCollection<T> generic class which implements generic IEnumerable<T>. The IEnumerable<T> in turn inherits non-generic IEnumerable.
using System.Collections;
public class MyCollection<T> : IEnumerable<T>
{
private T[] _items;
public MyCollection(T[] items)
{
_items = items;
}
// The strongly-typed generic method is public
public IEnumerator<T> GetEnumerator()
{
return new MyEnumerator<T>(_items);
}
// The legacy non-generic method required by inheritance is private
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}STEP2. MyEnumerator<T> generic class implements generic IEnumerator<T> which in turn inherits non-generic IEnumerator.public class MyEnumerator<T> : IEnumerator<T>
{
private T[] _items;
private int _position = -1;
public MyEnumerator(T[] items)
{
_items = items;
}
// Generic Current is a public, standard property
public T Current
{
get
{
if (_position < 0 || _position >= _items.Length)
{
throw new InvalidOperationException("Enumeration has either not started or has already finished.");
}
return _items[_position];
}
}
// Legacy non-generic Current implemented explicitly is private
object IEnumerator.Current => this.Current;
// Dispose cannot throw NotImplementedException, as foreach automatically calls it
public void Dispose()
{
// Nothing to clean up for a simple array, so we leave it empty.
}
// MoveNext should be public, not explicit
public bool MoveNext()
{
_position++;
return _position < _items.Length;
}
// Reset should be public, not explicit
public void Reset()
{
_position = -1;
}
}STEP3. Program class consumes MyCollection<T> class.public class Program
{
static void Main(string[] args)
{
string[] colors = { "red", "green", "blue", "pink" };
MyCollection<string> mycollection = new MyCollection<string>(colors);
IEnumerator<string> enumerator = mycollection.GetEnumerator();
while (enumerator.MoveNext())
{
Console.WriteLine(enumerator.Current);
}
}
}
red
green
blue
pink
In above example, note the explicit interface implementation for the legacy version. Why?
Because IEnumerable<T> inherits from IEnumerable, any class implementing the generic version must implement both GetEnumerator() methods. To avoid a name clash, C# developers use explicit interface implementation for the legacy version.
public class MyCollection<T> : IEnumerable<T>
{
// The modern, strongly-typed generic method
public IEnumerator<T> GetEnumerator()
{
// Return your generic enumerator here
}
// The legacy non-generic method required by inheritance
// It hides behind the interface to avoid cluttering your class API
IEnumerator IEnumerable.GetEnumerator()
{
// Simply call the generic version above
return this.GetEnumerator();
}
}
Note
- The legacy non generic property and methods are private and explicit interface implementation.
- The generic property and methods are public and implicit interface implementation.
- It is required to implement both generic and non generic interfaces, IEnumerable, IEnumerable<T>, IEnumerator, and IEnumerator<T>.
No comments:
Post a Comment