Home Search Contact us About us
Title Using the new foreach command.
Summary foreach is a new command for C and C++ developers new to the C# world. It allows objects to be iterated through.
Contributor John McTainsh
Published 13-May-2001
Last updated 13-May-2001
Page rating   80% for 9 votes Useless Brilliant
 Download Sample project files - 4 Kb

Description.

Unlike C++, C# has new command called foreach Delphi developers will be familiar with it so here is a small example of it for C++ developers. Help explains that it is used to iterate through a collections of objects. Since the command is very simple to used we will concentrate on building objects to work with it. The three object we will try will be.

  • A simple array.
  • A very simple class implementing the minimum code to iterate through the class.
  • A more standard implementation using an inner class to perform the iterating.

Here is the sample.

Here we see the code the iterator through the three lists. The first example also shows how the array is defines in C# and its iteration.

    using System.Collections;
    ...
    // Setup an array
    const string sFormatMask = "###,###";
    int  nNumLen = sFormatMask.Length;
    int[]  ary = new int [] { 10, 2345, 4, 238, 98765, 2 };

    Console.WriteLine("Array values");
    // Iterate through the array display the data
    foreach( int nAryValue in ary ) 
    {
        // Format the number for display
        string sNumFormatted = Int32.Format( nAryValue, sFormatMask );
        Console.WriteLine( sNumFormatted.PadLeft(nNumLen) );
    }

    Console.WriteLine();
    Console.WriteLine("Binary limits");

    // Iterate through the MyRoundBinary class
    MyRoundBinary mc = new MyRoundBinary();
    foreach( int nAryValue in mc ) 
    {
        // Format the number for display
        string sNumFormatted = Int32.Format( nAryValue, sFormatMask );
        Console.WriteLine( sNumFormatted.PadLeft(nNumLen) );
    }

    Console.WriteLine();
    Console.WriteLine("Saturdays in range");

    // Iterate through the Saturdays class
    Saturdays f = new Saturdays( new DateTime(2001,06,10), new DateTime(2001,07,30) );
    foreach( DateTime item in f)
    {
        Console.WriteLine(
            item.Format(
                "ddd dd-MMM-yyyy ", null  ) );
    }

This is the output from the above code.

Array values
     10
  2,345
      4
    238
 98,765
      2

Binary limits
      1
      2
      4
      8
     16
     32
     64
    128
    256

Saturdays in range
Sat 23-Jun-2001
Sat 30-Jun-2001
Sat 07-Jul-2001
Sat 14-Jul-2001
Sat 21-Jul-2001
Sat 28-Jul-2001

Simple iterating class.

If our needs are simple then with a little code you can create an iteratable class. The key points are to implement IEnumerable to tell your friends that you can be iterated and IEnumerator to do the iteration.

/// [summary]
/// This is a simple collection definition that enables an object
/// to be iterated through using the foreach command. The output
/// will be the list 1,2,4,8...,256. Usually you would seperate 
/// out the IEnumerator and IEnumerable wrappers but this is 
/// quite a simple implementation.
/// [/summary]
class MyRoundBinary : IEnumerable , IEnumerator
{
    int m_nBinarys;
    public MyRoundBinary() 
    {
        Reset();
    }

    /// [summary]
    /// Here we return ourselves as the Enumerator for ourselves.
    /// We can do this because the Iterator is part of this class.
    /// [/summary]
    public MyRoundBinary GetEnumerator()
    {
        return this;
    }

    /// [summary]
    /// Because this class implements it's own enumerator this
    /// functaion will never be called. It would usually be called
    /// by the above function.
    /// [/summary]
    IEnumerator IEnumerable.GetEnumerator() 
    {
        return null;
    }

    // These are the three basic enumeration fucntions.
    public void Reset() 
    {
        m_nBinarys = 0;
    }

    public bool MoveNext() 
    {
        if( m_nBinarys == 0 )
            m_nBinarys = 1;
        else
            m_nBinarys = m_nBinarys << 1; 
        return( m_nBinarys < 257 );
    }

    public int Current 
    {
        get 
        {
            return m_nBinarys;
        }
    }

    /// [summary]
    /// Because this class implements its own enumerator, this fuction
    /// is never called. The above function is called directly.
    /// [/summary]
    object IEnumerator.Current 
    {
        get 
        {
            return null;
        }
    }
}

The Standard iterating class.

If you are looking for the more socially acceptable implementation then you will need to create an inner class and pass that the outer class to read its data. This way the IEnumerator implementation is kept neatly packaged in the inner class. When an iteration is to be performed the GetEnumerator method is called. This method returns a new instance of the Enumerator (inner class) that perform the iteration without bothering the outer class.

/// [summary]
/// This class creates the ability to get the Saturdays for a date range
/// the inner class implements the ability to iterate through the
/// range.
/// [/summary]
class Saturdays : IEnumerable
{
    private DateTime m_dateStart;
    private DateTime m_dateEnd;

    // Constructor to set the date range limits
    public Saturdays( DateTime dateStart, DateTime dateEnd )
    {
        m_dateStart = dateStart;
        m_dateEnd   = dateEnd;
    }

    // Get access to the Enumerator for Saturdays
    public IEnumerator GetEnumerator()
    {
        return new SaturdayEnumerator(this);
    }

    /// [summary]
    /// Inner class implementing the Enumerator to enable iterating
    /// through the Saturdays.
    /// [/summary]
    private class SaturdayEnumerator : IEnumerator
    {   
        private DateTime m_dateCurrent;
        private Saturdays m_saturdays;

        // Constructor taking the outer class
        public SaturdayEnumerator(Saturdays saturdays)
        {
            this.m_saturdays = saturdays;
            Reset();
        }

        // Set the next value and return true if there is more data.
        public bool MoveNext()
        {

            m_dateCurrent = m_dateCurrent.AddDays( 7 );
            return( m_dateCurrent < m_saturdays.m_dateEnd ); 
        }

        // Set the start data.
        public void Reset()
        {
            m_dateCurrent = m_saturdays.m_dateStart;
            while( m_dateCurrent.DayOfWeek != 6 )
                m_dateCurrent = m_dateCurrent.AddDays( 1 );
        }

        // Read only access to the object data
        public object Current
        {
            get
            {
                return m_dateCurrent;
            }
        }
    }
}

Comments Date
Home Search Contact us About us