Поделиться через


Using Iterators (C# Programming Guide)

The most common way to create an iterator is to implement the GetEnumerator method on the IEnumerable interface, for example:

public System.Collections.IEnumerator GetEnumerator()
{
    for (int i = 0; i < 10; i++)
    {
        yield return i;
    }
}

The presence of the GetEnumerator method makes the type an enumerable type and allows using the foreach statement. If the method above was part of a class definition for ListClass, then it would be possible to use foreach on the class like this:

static void Main()
{
    ListClass listClass1 = new ListClass();

    foreach (int i in listClass1)
    {
        System.Console.Write(i + " ");
    }
    // Output: 0 1 2 3 4 5 6 7 8 9
}

The foreach statement invokes ListClass.GetEnumerator() and uses the returned enumerator to iterate through the values. For an example of how to create a generic iterator that returns a IEnumerator<T> interface, see How to: Create an Iterator Block for a Generic List (C# Programming Guide).

It is also possible to use named iterators to support different ways of iterating through the same collection of data. For example, you could provide one iterator which returns elements in ascending order, and one which returns elements in descending order. An iterator can also have parameters to enable clients to control all or part of the iteration behavior. The following iterator implements the IEnumerable interface using the named iterator SampleIterator:

// Implementing the enumerable pattern
public System.Collections.IEnumerable SampleIterator(int start, int end)
{
    for (int i = start; i <= end; i++)
    {
        yield return i;
    }
}

The named iterator is invoked like this:

ListClass test = new ListClass();

foreach (int n in test.SampleIterator(1, 10))
{
    System.Console.Write(n + " ");
}
// Output: 1 2 3 4 5 6 7 8 9 10

You can use more than one yield statement in the same iterator as in the following example:

public System.Collections.IEnumerator GetEnumerator()
{
    yield return "With an iterator, ";
    yield return "more than one ";
    yield return "value can be returned";
    yield return ".";
}

You can then print the results using the following foreach statement:

foreach (string element in new TestClass())
{
    System.Console.Write(element);
}
// Output: With an iterator, more than one value can be returned.

This example displays the following text:

With an iterator, more than one value can be returned.

On each successive iteration of the foreach loop (or the direct call to IEnumerator.MoveNext), the next iterator code body resumes after the previous yield statement and continues to the next until the end of the iterator body is reached, or a yield break statement is encountered.

Iterators do not support the IEnumerator.Reset method. To re-iterate from the beginning, you must obtain a new iterator.

Example

The following code contains all the examples from this topic.

namespace UsingIterators
{
    class Program
    {
        static void Main()
        {
            // Using a simple iterator.
            ListClass listClass1 = new ListClass();

            foreach (int i in listClass1)
            {
                System.Console.Write(i + " ");
            }
            // Output: 0 1 2 3 4 5 6 7 8 9
            System.Console.WriteLine();


            // Using a named iterator.
            ListClass test = new ListClass();

            foreach (int n in test.SampleIterator(1, 10))
            {
                System.Console.Write(n + " ");
            }
            // Output: 1 2 3 4 5 6 7 8 9 10
            System.Console.WriteLine();


            // Using multiple yield statements.
            foreach (string element in new TestClass())
            {
                System.Console.Write(element);
            }
            // Output: With an iterator, more than one value can be returned.
            System.Console.WriteLine();

        }
    }

    class ListClass : System.Collections.IEnumerable
    {

        public System.Collections.IEnumerator GetEnumerator()
        {
            for (int i = 0; i < 10; i++)
            {
                yield return i;
            }
        }

        // Implementing the enumerable pattern
        public System.Collections.IEnumerable SampleIterator(int start, int end)
        {
            for (int i = start; i <= end; i++)
            {
                yield return i;
            }
        }
    }

    class TestClass : System.Collections.IEnumerable
    {
        public System.Collections.IEnumerator GetEnumerator()
        {
            yield return "With an iterator, ";
            yield return "more than one ";
            yield return "value can be returned";
            yield return ".";
        }
    }
}

See Also

Tasks

How to: Create an Iterator Block for a List of Integers (C# Programming Guide)

How to: Create an Iterator Block for a Generic List (C# Programming Guide)

Reference

yield (C# Reference)

Using foreach with Arrays (C# Programming Guide)

foreach, in (C# Reference)

Concepts

C# Programming Guide