Click here to Skip to main content
15,892,674 members
Articles / Programming Languages / C# 4.0

Pick Your Enumerator & Me.Understand Yield and IEnumerable (C#)

Rate me:
Please Sign up or sign in to vote.
4.63/5 (16 votes)
21 Apr 2013CPOL18 min read 58.6K   410   25  
Using multiple enumerators and implementing IEnumerable with Yield or IEnumerator.
using System;
using System.Collections.Generic;

namespace IEnumerableCS
{
    /// <summary>
    /// A demonstration class that implements IEnumerable by means of Yield
    /// </summary>
    /// <remarks>Also shows how to choose between different enumeration methods at run time</remarks>
    public class ByYield : IEnumerable<double>
    {
        private double[,] _matrix;
        private MatrixEnumerator _matrixEnumerator;

        /// <summary>
        /// Creates the demonstration class using the supplied 2D array of double and sets the default enumeration method
        /// </summary>
        /// <param name="matrix">The 2D array of double(,) that will be used by this matrix class</param>
        /// <remarks></remarks>
        public ByYield(double[,] matrix)
        {
            this._matrix = matrix;
            this._matrixEnumerator = MatrixEnumerator.Horizontal;
        }

        /// <summary>
        /// Allows the choice of enumeration method at run time
        /// </summary>
        /// <value>An Enum representing the desired enumeration method</value>
        /// <returns>An Enum representing the current enumeration method</returns>
        /// <remarks></remarks>
        public MatrixEnumerator Enumerator
        {
            get { return this._matrixEnumerator; }
            set { this._matrixEnumerator = value; }
        }

        /// <summary>
        /// Returns a private class method consistent with the current value of <see cref="Enumerator">Enumerator</see>
        /// </summary>
        /// <returns>A private class method consistent with the current value of <see cref="Enumerator">Enumerator</see></returns>
        /// <remarks>The private classes methods are Iterator functions employing Yield</remarks>
        public IEnumerator<double> GetEnumerator()
        {
            switch (this._matrixEnumerator)
            {
                case MatrixEnumerator.Horizontal:
                    return this.HorizontalEnumerator();
                case MatrixEnumerator.Vertical:
                    return this.VerticalEnumerator();
                default:
                    throw new InvalidOperationException();
            }
        }

        /// <summary>
        /// [Use GetEnumerator instead] Returns a private class method consistent with the current value of <see cref="Enumerator">Enumerator</see>
        /// </summary>
        /// <returns>[Use GetEnumerator instead] A private class method consistent with the current value of <see cref="Enumerator">Enumerator</see></returns>
        /// <remarks>[Use GetEnumerator instead] The private classes methods are Iterator functions employing Yield</remarks>
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        /// <summary>
        /// An iterator function to provide Enumeration capability, enumerates the array by row
        /// </summary>
        /// <returns>A double representing the value of the current position in the array being enumerated</returns>
        /// <exception cref="InvalidOperationException">This exception is thrown if the <see cref="_matrix">field</see> is null</exception>
        private IEnumerator<double> VerticalEnumerator()
        {
            // Check that the matrix is not null before we try and iterate over it
            if (this._matrix != null)
            {
                // Since this is vertical enumeration the row needs to be the inner loop
                for (int col = 0; col <= this._matrix.GetUpperBound(1); col++)
                {
                    for (int row = 0; row <= this._matrix.GetUpperBound(0); row++)
                    {
                        // Now the magic bit, it's like a Return statement but...
                        yield return this._matrix[row, col];
                        // Stop here and wait until the function is called again, then continue on your way
                    }
                }
            } else {
                throw new InvalidOperationException();
            }
        }

        /// <summary>
        /// An iterator function to provide Enumeration capability, enumerates the array by column
        /// </summary>
        /// <returns>A double representing the value of the current position in the array being enumerated</returns>
        /// <exception cref="InvalidOperationException">This exception is thrown if the <see cref="_matrix">field</see> is null</exception>
        private IEnumerator<double> HorizontalEnumerator()
        {
            // Check that the matrix is not null before we try and iterate over it
            if (this._matrix != null)
            {
                // Since this is horizontal enumeration the column needs to be the inner loop
                for (int row = 0; row <= this._matrix.GetUpperBound(0); row++)
                {
                    for (int col = 0; col <= this._matrix.GetUpperBound(1); col++)
                    {
                        // Now the magic bit, it's like a Return statement but...
                        yield return this._matrix[row, col];
                        // Stop here and wait until the function is called again, then continue on your way
                    }
                }
            } else {
                throw new InvalidOperationException();
	        }
        }
    }


    /// <summary>
    /// A demonstration class that implements IEnumerable by means of IEnumerators
    /// </summary>
    /// <remarks>Also shows how to choose between different IEnumerator objects at run time</remarks>
    public class ByEnumerator : IEnumerable<double>
    {

        private double[,] _matrix;
        private MatrixEnumerator _matrixEnumerator;

        /// <summary>
        /// Creates the demonstration class using the supplied 2D array of double and sets the default enumeration class
        /// </summary>
        /// <param name="matrix">The 2D array of double(,) that will be used by this matrix class</param>
        /// <remarks></remarks>
        public ByEnumerator(double[,] matrix)
        {
            this._matrix = matrix;
            this._matrixEnumerator = MatrixEnumerator.Horizontal;
        }

        /// <summary>
        /// Allows the choice of enumeration method at run time
        /// </summary>
        /// <value>An Enum representing the desired enumeration method</value>
        /// <returns>An Enum representing the current enumeration method</returns>
        /// <remarks></remarks>
        public MatrixEnumerator Enumerator
        {
            get { return this._matrixEnumerator; }
            set { this._matrixEnumerator = value; }
        }

        /// <summary>
        /// Returns an IEnumerator object consistent with the current value of <see cref="Enumerator">Enumerator</see>
        /// </summary>
        /// <returns>An IEnumerator object consistent with the current value of <see cref="Enumerator">Enumerator</see></returns>
        public IEnumerator<double> GetEnumerator()
        {
            switch (this._matrixEnumerator)
            {
                case MatrixEnumerator.Vertical:
                    return new VerticalMatrixEnumerator(this._matrix);
                case MatrixEnumerator.Horizontal:
                    return new HorizontalMatrixEnumerator(this._matrix);
                default:
                    throw new InvalidOperationException();
            }
        }

        /// <summary>
        /// [Use GetEnumerator instead] Returns an IEnumerator object consistent with the current value of <see cref="Enumerator">Enumerator</see>
        /// </summary>
        /// <returns>[Use GetEnumerator instead] An IEnumerator object consistent with the current value of <see cref="Enumerator">Enumerator</see></returns>
        /// <remarks>[Use GetEnumerator instead]</remarks>
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
    }

    /// <summary>
    /// Enum representing the choice of enumerators for a 2D array
    /// </summary>
    /// <remarks></remarks>
    public enum MatrixEnumerator
    {
        Vertical,
        Horizontal
    }
} // Namespace

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Engineer
France France
A hobbyist begin-again-er!

Spent a few years longer ago than I care to remember with BBC Basic, a couple of years with Delphi about 10-15 years ago with a smattering af MS Access applications along the way. Dropped out of it completely except for the occasional Excel macro.

Finally picked up the baton again with VB.Net in VS2010 and now VS 2012and have been playing around quite a bit with a few odds and sodds, learning much as I go - and long may it continue.

I don't work even close to the IT industry and probably never will, but I do enjoy it as a hobby.

Comments and Discussions