This article provides C# code for an empty enumerator. This generic class can be used to simulate enumeration over an empty collection of any type of objects. Here is the code:
using System; using System.Collections; using System.Collections.Generic; public class EmptyEnumerator<T> : IEnumerator<T> { public T Current { get { return default(T); } } object IEnumerator.Current { get { return this.Current; } } public void Dispose() { } public bool MoveNext() { return false; } public void Reset() { } }
Empty Enumerator for Lazy Collections
An empty enumerator comes in handy for lazy collections. These are objects that contain a collection, but do not create the collection until it is necessary to add an object to that collection.
For example, consider this simple object “MyObject”:
public class MyObject { public MyObject() { } public MyObject( string name ) { this.Name = name; } public string Name; public override string ToString() { return this.Name; } }
Following is an example of a lazy collection. This “MyList” object contains a collection of MyObject’s, but doesn’t create the list until it is necessary in the “Add” method.
public class MyList : IEnumerable<MyObject> { public void Add( MyObject obj ) { if (obj != null) { if (this.m_List == null) this.m_List = new List<MyObject>(); this.m_List.Add( obj ); } } public int Count { get { return this.m_List == null ? 0 : this.m_List.Count; } } public IEnumerator<MyObject> GetEnumerator() { IEnumerator<MyObject> enumerator = null; if (this.m_List == null) enumerator = new EmptyEnumerator<MyObject>(); else enumerator = this.m_List.GetEnumerator(); return enumerator; } IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } private List<MyObject> m_List; public void Remove( MyObject obj ) { if (obj != null && this.m_List != null) this.m_List.Remove( obj ); } }
But what happens if the user wants to enumerate over MyList when it’s empty? There is no enumerator because the collection hasn’t been created yet. Hence, if there is no collection, instead we return an EmptyEnumerator:
public IEnumerator<MyObject> GetEnumerator() { IEnumerator<MyObject> enumerator = null; if (this.m_List == null) enumerator = new EmptyEnumerator<MyObject>(); else enumerator = this.m_List.GetEnumerator(); return enumerator; }
Ternary Operator Doesn’t Work
One interesting thing to notice in the “GetEnumerator” method is the if-else block. You might be tempted to write it with a ternary operator as follows:
public IEnumerator<MyObject> GetEnumerator() { return this.m_List == null ? new EmptyEnumerator<MyObject>() : this.m_List.GetEnumerator(); }
But this generates a compiler error:
Type of conditional expression cannot be determined because there is no implicit conversion between ‘EmptyEnumerator<EnumerableEmpty.MyObject>’ and ‘System.Collections.Generic.List<EnumerableEmpty.MyObject>.Enumerator’
Simple Example
Here is a simple console program to demonstrate this concept:
class Program { static void Main( string[] args ) { MyList list = new MyList(); Write( list ); list.Add( new MyObject( "Luke Skywalker" ) ); Write( list ); list.Add( new MyObject( "Darth Vader" ) ); list.Add( new MyObject( "Yoda" ) ); Write( list ); Console.ReadLine(); } static void Write( MyList list ) { Console.WriteLine( "List Count={0}", list.Count ); foreach (MyObject obj in list) { Console.WriteLine( obj ); } Console.WriteLine(); } }
And the console output would be:
List Count=0
List Count=1
Luke SkywalkerList Count=3
Luke Skywalker
Darth Vader
Yoda
Why Not To Use Enumerable.Empty() Generic Method?
Because Enumerable.Empty() is only available in System.Linq in .NET 3.5. Unfortunately, desktop commercial vendors such as myself are stuck with .NET 2.0 for the forseeable future. Here’s why:
http://www.devtopics.com/fat-net/
The Good Theme Site
What a great forum this and http://www.devtopics.com and excellent resource you have.
[…] C# Empty Enumerator (Timm Webb) […]
Simpler implementation:
public static IEnumerator GetEmptyEnumerator()
{
yield break;
}
Oh the joys of iterator blocks 🙂
Jon
(That should be GetEmptyEnumerator() of course.)
Jon
[…] Timm Martin talks in depth about the C# Empty Enumerator. […]
Unless you need to instrument the enumerator, wouldn’t
private static readonly T[] empty = new T[];
and
return empty.GetEnumerator();
be a simpler approach?
timm, you can include the System.Core dll in your own .net 2.0 install, see comment #12 on the page you gave a link for. Then you can build on .net 3.5, but you provide the needed libraries for ppl with only .net 2.0
This is complete unnecessary. Just initialize your list to an empty list instead of null. kisS. Emphasis on that last S.
The example probably works fine in practice, but technically, it is broken.
clearly states that ‘Current’ must throw an exception after ‘MoveNext’ returned false. I also read that page as if it should throw if called before ‘MoveNext’ were called.
The documentation is unclear as to what exception this should throw.