【已更新最新开发文章,点击查看详细】

  迭代器可用于逐步迭代集合,例如列表和数组。

下次调用迭代器函数时,将从该位置重新开始执行。

foreach 语句或 LINQ 查询从客户端代码中使用迭代器。

到达迭代器方法的结尾时,循环便已完成。

static void Main()
{
    foreach (int number in SomeNumbers())
    {
        Console.Write(number.ToString() + " ");
    }
    // 输出: 3 5 8
    Console.ReadKey();
}

public static System.Collections.IEnumerable SomeNumbers()
{
    yield return 3;
    yield return 5;
    yield return 8;
}

IEnumerator<T>。

可以使用 yield break 语句来终止迭代。

对于本主题中除简单迭代器示例以外的所有示例,请为 System.Collections 和 System.Collections.Generic 命名空间加入 using 指令。

简单的迭代器
 Main 中,foreach 语句体的每次迭代都会创建一个对迭代器函数的调用,并将继续到下一个 yield return 语句。
static void Main()
{
    foreach (int number in EvenSequence(5, 18))
    {
        Console.Write(number.ToString() + " ");
    }
    // 输出: 6 8 10 12 14 16 18
    Console.ReadKey();
}

public static System.Collections.Generic.IEnumerable<int> EvenSequence(int firstNumber, int lastNumber)
{
    // 迭代集合中的偶数.
    for (int number = firstNumber; number <= lastNumber; number++)
    {
        if (number % 2 == 0)
        {
            yield return number;
        }
    }
}
创建集合类

IEnumerator。

GetEnumerator 方法通过使用 yield return 语句每次返回 1 个字符串。

static void Main()
{
    DaysOfTheWeek days = new DaysOfTheWeek();

    foreach (string day in days)
    {
        Console.Write(day + " ");
    }
    // 输出: Sun Mon Tue Wed Thu Fri Sat
    Console.ReadKey();
}

public class DaysOfTheWeek : IEnumerable
{
    private string[] days = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };

    public IEnumerator GetEnumerator()
    {
        for (int index = 0; index < days.Length; index++)
        {
            // 迭代每一天
            yield return days[index];
        }
    }
}

下例创建了一个包含动物集合的 Zoo 类。

引用 BirdsMammals 属性的 foreach 语句使用 AnimalsForType 命名迭代器方法。

 1 static void Main()
 2 {
 3     Zoo theZoo = new Zoo();
 4 
 5     theZoo.AddMammal("Whale");
 6     theZoo.AddMammal("Rhinoceros");
 7     theZoo.AddBird("Penguin");
 8     theZoo.AddBird("Warbler");
 9 
10     foreach (string name in theZoo)
11     {
12         Console.Write(name + " ");
13     }
14     Console.WriteLine();
15     // 输出: Whale Rhinoceros Penguin Warbler
16 
17     foreach (string name in theZoo.Birds)
18     {
19         Console.Write(name + " ");
20     }
21     Console.WriteLine();
22     // 输出: Penguin Warbler
23 
24     foreach (string name in theZoo.Mammals)
25     {
26         Console.Write(name + " ");
27     }
28     Console.WriteLine();
29     // 输出: Whale Rhinoceros
30 
31     Console.ReadKey();
32 }
33 
34 public class Zoo : IEnumerable
35 {
36     // 私有成员
37     private List<Animal> animals = new List<Animal>();
38 
39     // 公共方法
40     public void AddMammal(string name)
41     {
42         animals.Add(new Animal { Name = name, Type = Animal.TypeEnum.Mammal });
43     }
44 
45     public void AddBird(string name)
46     {
47         animals.Add(new Animal { Name = name, Type = Animal.TypeEnum.Bird });
48     }
49 
50     public IEnumerator GetEnumerator()
51     {
52         foreach (Animal theAnimal in animals)
53         {
54             yield return theAnimal.Name;
55         }
56     }
57 
58     // 公共成员
59     public IEnumerable Mammals
60     {
61         get { return AnimalsForType(Animal.TypeEnum.Mammal); }
62     }
63 
64     public IEnumerable Birds
65     {
66         get { return AnimalsForType(Animal.TypeEnum.Bird); }
67     }
68 
69     // 私有方法
70     private IEnumerable AnimalsForType(Animal.TypeEnum type)
71     {
72         foreach (Animal theAnimal in animals)
73         {
74             if (theAnimal.Type == type)
75             {
76                 yield return theAnimal.Name;
77             }
78         }
79     }
80 
81     // 私有类
82     private class Animal
83     {
84         public enum TypeEnum { Bird, Mammal }
85 
86         public string Name { get; set; }
87         public TypeEnum Type { get; set; }
88     }
89 }
对泛型列表使用迭代器

GetEnumerator 方法通过使用 yield return 语句返回数组值。

非泛型实现遵从泛型实现的规则。

这些命名迭代器为 TopToBottomBottomToTop 属性,以及 TopN 方法。

BottomToTop 属性在 get 访问器中使用迭代器。

  1 static void Main()
  2 {
  3     Stack<int> theStack = new Stack<int>();
  4 
  5     //  向堆栈中添加项
  6     for (int number = 0; number <= 9; number++)
  7     {
  8         theStack.Push(number);
  9     }
 10 
 11     // 从堆栈中检索项。
 12     // 此处允许使用 foreach,因为 foreach 实现了 IEnumerable<int>
 13     foreach (int number in theStack)
 14     {
 15         Console.Write("{0} ", number);
 16     }
 17     Console.WriteLine();
 18     // 输出: 9 8 7 6 5 4 3 2 1 0
 19 
 20     // 此处允许使用 foreach,因为 theStack.TopToBottom 属性返回了 IEnumerable(Of Integer).
 21     foreach (int number in theStack.TopToBottom)
 22     {
 23         Console.Write("{0} ", number);
 24     }
 25     Console.WriteLine();
 26     // 输出: 9 8 7 6 5 4 3 2 1 0
 27 
 28     foreach (int number in theStack.BottomToTop)
 29     {
 30         Console.Write("{0} ", number);
 31     }
 32     Console.WriteLine();
 33     // 输出: 0 1 2 3 4 5 6 7 8 9
 34 
 35     foreach (int number in theStack.TopN(7))
 36     {
 37         Console.Write("{0} ", number);
 38     }
 39     Console.WriteLine();
 40     // 输出: 9 8 7 6 5 4 3
 41 
 42     Console.ReadKey();
 43 }
 44 
 45 public class Stack<T> : IEnumerable<T>
 46 {
 47     private T[] values = new T[100];
 48     private int top = 0;
 49 
 50     public void Push(T t)
 51     {
 52         values[top] = t;
 53         top++;
 54     }
 55     public T Pop()
 56     {
 57         top--;
 58         return values[top];
 59     }
 60 
 61     // 此方法实现了GetEnumerator()方法. 它允许在 foreach 语句中使用类的实例。
 63     public IEnumerator<T> GetEnumerator()
 64     {
 65         for (int index = top - 1; index >= 0; index--)
 66         {
 67             yield return values[index];
 68         }
 69     }
 70 
 71     IEnumerator IEnumerable.GetEnumerator()
 72     {
 73         return GetEnumerator();
 74     }
 75 
 76     public IEnumerable<T> TopToBottom
 77     {
 78         get { return this; }
 79     }
 80 
 81     public IEnumerable<T> BottomToTop
 82     {
 83         get
 84         {
 85             for (int index = 0; index <= top - 1; index++)
 86             {
 87                 yield return values[index];
 88             }
 89         }
 90     }
 91 
 92     public IEnumerable<T> TopN(int itemsFromTop)
 93     {
 94         // 如有必要,返回少于 itemsFromTop 
 95         int startIndex = itemsFromTop >= top ? 0 : top - itemsFromTop;
 96 
 97         for (int index = top - 1; index >= startIndex; index--)
 98         {
 99             yield return values[index];
100         }
101     }
102 
103 }
语法信息

不能在事件、实例构造函数、静态构造函数或静态终结器中使用迭代器。

必须存在从 yield return 语句中的表达式类型到迭代器返回的 IEnumerable<T> 类型参数的隐式转换。

在 C# 中,迭代器方法不能有任何 inrefout 参数。

在 C# 中,“yield”不是保留字,只有在 returnbreak 关键字之前使用时才有特殊含义。

技术实现

只要客户端代码中的 foreach 循环继续,此类就会跟踪迭代器的位置。

若要查看编译器执行的操作,可使用 Ildasm.exe 工具查看为迭代器方法生成的 Microsoft 中间语言代码。

IEnumerator<T> 接口的 CurrentMoveNextDispose 方法。

然后继续下一个 yield return 语句,直至到达迭代器体的结尾,或直至遇到 yield break 语句。

NotSupportedException。

C# 语言规范。

迭代器的使用

需执行以下操作时,这可能很有用:

  • 在第一次 foreach 循环迭代之后,修改列表序列。

  • EnumerateFiles 方法,该方法在 .NET Framework 中实现迭代器。

  • 使用迭代器方法,可生成该列表,然后在循环中产出每个结果。

 

【已更新最新开发文章,点击查看详细】

相关文章: