IEnumerable and IEnumerator Types

Problem
You want to know how to use IEnumerable and IEnumerator to enumerate objects of a specific type.

Solution
Implement a private nested class using the TypnameEnumerator convention.

Comments
Using a private nested type for enumerator classes is a good idea because these types are typically used with their enclosing type.

Example
Use the IEnumerable type to enumerate prime numbers in a loop.

public class PrimeNumbers : IEnumerable
{
    private readonly int _maxPrime;

    public PrimeNumbers(int maxPrime)
    {
        _maxPrime = maxPrime;
    }

    public IEnumerator GetEnumerator()
    {
        return new PrimeNumbersEnumerator(this);
    }

    private class PrimeNumbersEnumerator : IEnumerator
    {
        // Store reference to the enclosing object.
        private readonly PrimeNumbers _parent;

        // The last prime found.
        private int _currentValue = -1;

        // Store all prime numbers found so far except 2.
        private readonly ArrayList _primes = new ArrayList();

        public PrimeNumbersEnumerator(PrimeNumbers parent)
        {
            // Maintain a reference to the object being enumerated.
            _parent = parent;
        }

        public bool MoveNext()
        {
            if (_currentValue < 0)
            {
                // The first prime number is 2.
                _currentValue = 2;
            }
            else if (_currentValue == 2)
            {
                // The second prime number is 3.
                _currentValue = 3;
                _primes.Add(_currentValue);
            }
            else
            {
                // Test all odd numbers after the current value.
                var number = _currentValue;
                while (true)
                {
                    number += 2;
                    var isPrime = true;

                    foreach (int prime in _primes)
                    {
                        if ((number % prime) == 0)
                        {
                            isPrime = false;
                            break;
                        }
                        else if (prime * prime > number)
                        {
                            break;
                        }
                    }

                    // Check if a divisor has been found.
                    // Remember the number and add it to the list of found prime numbers.
                    if (!isPrime) continue;
                    _currentValue = number;
                    _primes.Add(_currentValue);
                    break;
                }
            }

            // If the number found is prime, then return true.
            return _currentValue <= _parent._maxPrime;
        }

        public object Current => _currentValue;

        // Set the enumerator to its initial position.
        public void Reset()
        {
        }
    }
}

Using the PrimeNumbers type to display all prime numbers that are less than 5000.

internal static class Program
{
    public static void Main()
    {
        foreach (int number in new PrimeNumbers(5000))
        {
            Console.WriteLine(number);
        }
    }
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s