使用迭代器(C# 编程指南)

创建迭代器最常用的方法是对 IEnumerable 接口实现 GetEnumerator 方法,例如:

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

GetEnumerator 方法的存在使得类型成为可枚举的类型,并允许使用 foreach 语句。 如果上面的方法是 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# 编程指南)

还可以使用命名的迭代器以支持通过不同的方式循环访问同一数据集合。 例如,您可以提供一个按升序返回元素的迭代器,而提供按降序返回元素的另一个迭代器。 迭代器还可以带有参数,以便允许客户端控制全部或部分迭代行为。 下面的迭代器使用命名的迭代器 SampleIterator 实现 IEnumerable 接口:

// 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# 编程指南