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”:
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 MyObject { public MyObject() { } public MyObject( string name ) { this.Name = name; } public string Name; public override string ToString() { return this.Name; } }
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 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 ); } }
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:But this generates a compiler error:public IEnumerator<MyObject> GetEnumerator() { return this.m_List == null ? new EmptyEnumerator<MyObject>() : this.m_List.GetEnumerator(); }
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:And the console output would be: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(); } }
List Count=0
List Count=1
Luke Skywalker
List Count=3
Luke Skywalker
Darth Vader
Yoda
No comments:
Post a Comment