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 Skywalker

List Count=3
Luke Skywalker
Darth Vader
Yoda

Share and Enjoy:
  • Digg
  • Twitter
  • Facebook
  • Reddit
  • StumbleUpon
  • LinkedIn
  • Google Bookmarks
  • Slashdot