Object Oriented Programming Patterns for Geeks

The Iterator Pattern

 

namespace ooppatterns
{
    using System;
    using System.Collections;
    using System.Collections.Generic;

    internal class Program
    {
        private static void Main( string[] args )
        {
            // Create something to enumerate.
            List<string> str = new List<string>();

            str.AddRange( new string[] 
                            { 
                                ".NET", 
                                "Iterators", 
                                "are", 
                                "all", 
                                "you", 
                                "need" 
                            } );


            // Demonstrate basic .NET implementation
            Console.WriteLine( ".NET c# shortcut syntax" );
            Console.WriteLine( new string( '-', 30 ) );

            foreach ( string val in str )
                Console.WriteLine( val );

            // Demonstrate above in longhand (A)
            Console.WriteLine( "\nDirect implementation Syntax (A)" );
            Console.WriteLine( new string( '-', 30 ) );

            for ( IEnumerator<string> enm = str.GetEnumerator(); enm.MoveNext(); )
                Console.WriteLine( enm.Current );

            // Demonstrate above in longhand (B)
            Console.WriteLine( "\nDirect implementation Syntax (B)" );
            Console.WriteLine( new string( '-', 30 ) );

            IEnumerator<string> enmB = str.GetEnumerator();

            while ( enmB.MoveNext() )
                Console.WriteLine( enmB.Current );


            // Demonstrate the use of a custom enumerator with an added feature.
            //    the basic .NET implementation uses a .NET 'out-of-the-box' version.
            Console.WriteLine( "\nCustom implementation - forward" );
            Console.WriteLine( new string( '-', 30 ) );

            for (    IEnumerator<string> enm = new myEnum( str, Direction.Forward ); 
                    enm.MoveNext(); 
            )
                Console.WriteLine( enm.Current );

            Console.WriteLine( "\nCustom implementation - backward" );
            Console.WriteLine( new string( '-', 30 ) );

            for (    IEnumerator<string> enm = new myEnum( str, Direction.Backward ); 
                    enm.MoveNext(); 
            )
                Console.WriteLine( enm.Current );


            // Demonstrate the .NET 2.0 'yield' ability shorthand...
            Console.WriteLine( "\n.NET c# shortcut using 'yield' to "
                                + @"retrieve INDEX MOD 2 == 0 - forward" );
            Console.WriteLine( new string( '-', 30 ) );

            foreach ( string val in HandleList.GetMod2EvenForward( str ) )
                Console.WriteLine( val );

            Console.WriteLine( "\n.NET c# shortcut using 'yield' to "
                                + @"retrieve INDEX MOD 2 == 1 - backward" );
            Console.WriteLine( new string( '-', 30 ) );

            foreach ( string val in HandleList.GetMod2OddBackword( str ) )
                Console.WriteLine( val );


            // Demonstrate the .NET 2.0 'yield' ability longhand...
            Console.WriteLine( "\nCustom implementation using 'yield' to "
                                + @"retrieve INDEX MOD 2 == 0 - forward" );
            Console.WriteLine( new string( '-', 30 ) );

            for (    IEnumerator<string> enm 
                    = HandleList.GetMod2EvenForward( str ).GetEnumerator(); 
                    enm.MoveNext(); 
            )
                Console.WriteLine( enm.Current );

            Console.WriteLine( "\nCustom implementation using 'yield' to "
                                + @"retrieve INDEX MOD 2 == 1 - backward" );
            Console.WriteLine( new string( '-', 30 ) );

            for (    IEnumerator<string> enm 
                    = HandleList.GetMod2OddBackword( str ).GetEnumerator(); 
                    enm.MoveNext(); 
            )
                Console.WriteLine( enm.Current );

            Console.ReadLine();
        }
    }

    enum Direction
    {
        Forward,
        Backward
    }

    // Custom Enumerator with the added feature to
    // allow you to enumerate the contents forwards OR backwards.
    class myEnum : IEnumerator<string>
    {
        private List<string> _collection;
        private int _index;
        private Direction _direction;

        public myEnum( List<string> collection, Direction direction )
        {
            this._collection = collection;
            this._direction = direction;

            this.Reset();
        }

        // This has been added to allow some trickery with
        // the 'yield' example.
        public int Index
        {
            get { return this._index; }
        }

        public string Current
        {
            get { return this._collection[this._index]; }
        }

        public void Dispose() { }

        object IEnumerator.Current
        {
            get { return this.Current; }
        }

        public bool MoveNext()
        {
            if ( this._direction == Direction.Forward )
            {
                this._index++;

                return this._index < this._collection.Count;
            }
            else
            {
                this._index--;

                return this._index >= 0;
            }
        }

        public void Reset()
        {
            if ( this._direction == Direction.Forward )
                this._index = -1;
            else
                this._index = this._collection.Count;
        }
    }

    // Demonstrate the usage of the yield keyword...
    //    NB: This is really just syntactic sugar supplied by the compiler.
    //        To see how it is implemented after compilation, please use
    //        Lutz Roeder's reflector.
    static class HandleList
    {
        public static IEnumerable<string> GetMod2EvenForward( List<string> list )
        {
            for ( myEnum enm 
                  = new myEnum( list, Direction.Forward );
                  enm
.MoveNext(); ) if ( enm.Index % 2 == 0 ) yield return enm.Current; } public static IEnumerable<string> GetMod2OddBackword( List<string> list ) { for ( myEnum enm
                  = new myEnum( list, Direction.Backward );
                  enm
.MoveNext(); ) if ( enm.Index % 2 == 1 ) yield return enm.Current; } } }