Использование итераторов (Руководство по программированию в C#)

Наиболее простой способ создания итератора заключается в реализации метода GetEnumerator для интерфейса IEnumerable, например:

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

Наличие метода GetEnumerator создает тип перечисляемого типа и позволяет использовать оператор foreach statement. Если бы приведенный выше метод был частью определения класса для ListClass, то можно было бы использовать foreach для класса следующим образом:

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
}

Оператор foreach вызывает ListClass.GetEnumerator() и использует возвращенный перечислитель для итерации значений. Пример создания универсального итератора, возвращающего интерфейс IEnumerator<T>, см. в разделе Практическое руководство. Создание блока итератора для общего списка (Руководство по программированию на C#).

Кроме того, можно использовать именованные итераторы в поддержку различных возможностей перебора одной и той же коллекции данных. Например, можно было бы предоставить один итератор, возвращающий элементы по возрастанию, а другой итератора, возвращающий элементы по убыванию. Итератор может также иметь параметры, позволяющие клиентам управлять всем поведением итератора или его часть. Следующий итератор реализует интерфейс IEnumerable при помощи именованного итератора SampleIterator:

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

Именованный итератор вызывается следующим образом.

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

В одном итераторе можно использовать несколько операторов yield, как в следующем примере.

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

Результаты можно вывести с помощью оператора foreach.

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

В этом примере приведен следующий текст.

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

В каждой последовательной итерации цикла foreach (или прямом вызове IEnumerator.MoveNext) следующий текст кода итератора возобновляется после оператора yield и продолжается до конца текста итератора или до оператора yield break.

Итераторы не поддерживают метод IEnumerator.Reset. Для повторной итерации сначала необходимо получить новый итератор.

Пример

В следующем коде содержатся все примеры данного раздела.

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 ".";
        }
    }
}

См. также

Задачи

Практическое руководство. Создание блока итератора для списка целых чисел (Руководство по программированию в C#)

Практическое руководство. Создание блока итератора для общего списка (Руководство по программированию на C#)

Ссылки

yield (справочник по C#)

Использование оператора foreach с массивами (Руководство по программированию на C#)

foreach, in (Справочник по C#)

Основные понятия

Руководство по программированию на C#