系列目录    【已更新最新开发文章,点击查看详细】 <https://www.cnblogs.com/SavionZhang/p/11229640.html>
  迭代器可用于逐步迭代集合,例如列表和数组。
  迭代器方法或 get 访问器可对集合执行自定义迭代。 迭代器方法使用 yield return 
<https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/yield>
 语句返回元素,每次返回一个。到达 yield return 语句时,会记住当前在代码中的位置。 下次调用迭代器函数时,将从该位置重新开始执行。
通过 foreach 
<https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/foreach-in>
 语句或 LINQ 查询从客户端代码中使用迭代器。
  在以下示例中,foreach 循环的首次迭代导致 SomeNumbers 迭代器方法继续执行,直至到达第一个 yield return 语句。 
此迭代返回的值为 3,并保留当前在迭代器方法中的位置。在循环的下次迭代中,迭代器方法的执行将从其暂停的位置继续,直至到达 yield return 
语句后才会停止。此迭代返回的值为 5,并再次保留当前在迭代器方法中的位置。 到达迭代器方法的结尾时,循环便已完成。
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; } 
迭代器方法或 get 访问器的返回类型可以是 IEnumerable 
<https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.ienumerable>、
IEnumerable<T> 
<https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.generic.ienumerable-1>
、IEnumerator 
<https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.ienumerator> 或 
IEnumerator<T> 
<https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.generic.ienumerator-1>
。
可以使用 yield break 语句来终止迭代。
对于本主题中除简单迭代器示例以外的所有示例,请为 System.Collections 和 System.Collections.Generic 
命名空间加入 using 指令。
简单的迭代器  下例包含一个位于 for 
<https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/for>
 循环内的yield return 语句。 在 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; } } } 创建集合类 
在以下示例中,DaysOfTheWeek 类实现 IEnumerable 
<https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.ienumerable> 
接口,此操作需要GetEnumerator 
<https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.ienumerable.getenumerator>
 方法。编译器隐式调用 GetEnumerator 方法,此方法返回 IEnumerator 
<https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.ienumerator>。
GetEnumerator 方法通过使用 yield return 语句每次返回 1 个字符串。
static void Main() { DaysOfTheWeek days = new DaysOfTheWeek(); foreach (string 
dayin 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 类。
引用类实例 (theZoo) 的 foreach 语句隐式调用 GetEnumerator 方法。 引用 Birds 和 Mammals 属性的 
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 theAnimalin 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 } 对泛型列表使用迭代器 
在以下示例中,Stack<T> 
<https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.generic.stack-1>
 泛型类实现IEnumerable<T> 
<https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.generic.ienumerable-1>
 泛型接口。Push 
<https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.generic.stack-1.push>
 方法将值分配给类型为T 的数组。 GetEnumerator 
<https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.generic.ienumerable-1.getenumerator>
 方法通过使用yield return 语句返回数组值。
除了泛型 GetEnumerator 
<https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.generic.ienumerable-1.getenumerator>
 方法,还必须实现非泛型GetEnumerator 
<https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.ienumerable.getenumerator>
 方法。这是因为从 IEnumerable 
<https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.ienumerable> 继承了
IEnumerable<T> 
<https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.generic.ienumerable-1>
。非泛型实现遵从泛型实现的规则。
本示例使用命名迭代器来支持通过各种方法循环访问同一数据集合。 这些命名迭代器为 TopToBottom 和 BottomToTop 属性,以及 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 } 语法信息 
迭代器可用作一种方法,或一个 get 访问器。 不能在事件、实例构造函数、静态构造函数或静态终结器中使用迭代器。
必须存在从 yield return 语句中的表达式类型到迭代器返回的 IEnumerable<T> 类型参数的隐式转换。
在 C# 中,迭代器方法不能有任何 in、ref 或 out 参数。
在 C# 中,“yield”不是保留字,只有在 return 或 break 关键字之前使用时才有特殊含义。
技术实现 
即使将迭代器编写成方法,编译器也会将其转换为实际上是状态机的嵌套类。 只要客户端代码中的 foreach 循环继续,此类就会跟踪迭代器的位置。
若要查看编译器执行的操作,可使用 Ildasm.exe 工具查看为迭代器方法生成的 Microsoft 中间语言代码。
为类 
<https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/class>
或结构 
<https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/struct>
创建迭代器时,不必实现整个IEnumerator 
<https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.ienumerator> 接口。
编译器检测到迭代器时,会自动生成IEnumerator 
<https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.ienumerator> 或 
IEnumerator<T> 
<https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.generic.ienumerator-1>
 接口的Current、MoveNext 和 Dispose 方法。
在 foreach 循环(或对 IEnumerator.MoveNext 的直接调用)的每次后续迭代中,下一个迭代器代码体都会在上一个 yield 
return 语句之后恢复。 然后继续下一个 yield return 语句,直至到达迭代器体的结尾,或直至遇到 yield break 语句。
迭代器不支持 IEnumerator.Reset 
<https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.ienumerator.reset>
 方法。若要从头开始重新迭代,必须获取新的迭代器。 在迭代器方法返回的迭代器上调用 Reset 
<https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.ienumerator.reset>
 会引发NotSupportedException 
<https://docs.microsoft.com/zh-cn/dotnet/api/system.notsupportedexception>。
有关其他信息,请参阅 C# 语言规范 
<https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/language-specification/classes#iterators>
。
迭代器的使用 
需要使用复杂代码填充列表序列时,使用迭代器可保持 foreach 循环的简单性。 需执行以下操作时,这可能很有用:
 * 
在第一次 foreach 循环迭代之后,修改列表序列。
 * 
避免在 foreach 循环的第一次迭代之前完全加载大型列表。 一个示例是用于加载一批表格行的分页提取。 另一个示例关于 EnumerateFiles 
<https://docs.microsoft.com/zh-cn/dotnet/api/system.io.directoryinfo.enumeratefiles>
 方法,该方法在 .NET Framework 中实现迭代器。
 * 
在迭代器中封装生成列表。 使用迭代器方法,可生成该列表,然后在循环中产出每个结果。
其他内容请参阅
 * System.Collections.Generic 
<https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.generic> 
 * IEnumerable<T> 
<https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.generic.ienumerable-1>
 * foreach, in 
<https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/foreach-in>
 * yield 
<https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/yield>
 * 对数组使用 foreach 
<https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/arrays/using-foreach-with-arrays>
 * 泛型 
<https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/generics/index>
 
系列目录    【已更新最新开发文章,点击查看详细】 
<https://www.cnblogs.com/SavionZhang/p/11229640.html>
热门工具 换一换
