1、枚举器和可枚举类型
为什么数组可以使用 foreach 来遍历自己的元素呢?原因是数组可以按需提供一个叫做枚举器(enumerator)的对象。获取对象枚举器的方法是通过调用对象的 GetEnumerator 方法。实现GetEnumerator 方法的类型叫做可枚举类型。

foreach 结构设计用来和可枚举类型一起使用,比如数组,它就会执行以下行为:
-通过调用 GetEnumerator 方法获取对象的枚举器
-从枚举器中请求每一项并且把它作为迭代变量(iteration variable),代码可以读取该变量但不可以改变。

2、IEnumerator 接口
实现了 IEnumerator 接口的枚举器包含 3 个函数成员:Current、MoveNext 以及 Reset。
Current 时返回序列中当前位置项的属性(只读,返回Object 的引用,所以可以返回任何类型的对象)
MoveNext 是把枚举器位置前进到集合中下一项的方法(有效返回True,无效 False,初始位置在序列的第一项之前,所以在第一次使用 Current 之前要先调用 MoveNext )
Reset 是把位置重置为初始状态的方法
如此便可以得到与 foreach 方法相近的方法:
1 int[] arr1 = { 10, 11, 12, 13 }; // Create an array.
2
3 IEnumerator ie = arr1.GetEnumerator(); //获取并存储枚举器
4
5 while (ie.MoveNext())
6 {
7 int item = (int)ie.Current; //获取当前项
8 Console.WriteLine($"Item value: { item }"); // Write it out.
9 }
3、IEnumerable 接口
可枚举类是指实现了 IEnumerable 接口的类。此接口只有一个成员——GetEnumerator 方法
public IEbumerator GetEnumerator{ … }
自己实现可枚举类:
实现 IEnumerator 接口的枚举器(实现 Current、MoveNext 和 Reset 方法)
实现 IEnumerable 接口的枚举类(实现 GetEnumerator 方法)
实现对应的方法是重点
4、泛型枚举接口

非泛型接口的实现是类型不安全的,它返回的是Object的引用,然后再转化为实际类型;泛型接口的枚举器是类型安全的,它返回实际类型的引用。
5、迭代器
yield return 指定序列中要返回的下一项
yield return 指定在序列中没有其他项
根据指定的返回类型,可以让迭代器产生枚举器或可枚举类型
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 MyClass mc = new MyClass();
6 foreach (string shade in mc)
7 Console.Write($"{shade} ");
8
9 foreach (string shade in mc.BlackAndWhite())
10 Console.Write($"{shade} ");
11 }
12 }
13 class MyClass
14 {
15
16 public IEnumerator<string> GetEnumerator()
17 {
18 IEnumerable<string> myEnumerable = BlackAndWhite();
19 return myEnumerable.GetEnumerator();
20 }
21 public IEnumerable<string> BlackAndWhite()
22 {
23 yield return "black";
24 yield return "gray";
25 yield return "white";
26 }
27 }
当我们实现返回枚举器的迭代器时,必须通过GetEnumertor方法来让类可枚举,它返回由迭代器返回的枚举器。
如果我们在类中实现迭代器返回可枚举类型,我们可以让类实现GetEnumerator来让类本身可被枚举,或者不实现GetEnumerator,让类不可枚举,只需要直接调用迭代器方法进行foreach枚举。
6、创建多个可枚举类型
1 class Spectrum
2 {
3 string[] colors = { "violet", "blue", "cyan", "green", "yellow", "orange", "red" };
4
5 public IEnumerable<string> UVtoIR()
6 {
7 for (int i = 0; i < colors.Length; i++)
8 yield return colors[i];
9 }
10
11 public IEnumerable<string> IRtoUV()
12 {
13 for (int i = colors.Length - 1; i >= 0; i--)
14 yield return colors[i];
15 }
16 }
17
18 class Program
19 {
20 static void Main()
21 {
22 Spectrum spectrum = new Spectrum();
23
24 foreach (string color in spectrum.UVtoIR())
25 Console.Write($"{ color } ");
26 Console.WriteLine();
27
28 foreach (string color in spectrum.IRtoUV())
29 Console.Write($"{ color } ");
30 Console.WriteLine();
31 }
32 }
7、创建多个枚举器,并把迭代器作为属性
1 using System;
2 using System.Collections.Generic;
3 class Spectrum
4 {
5 bool _listFromUVtoIR;
6 string[] colors = { "violet", "blue", "cyan", "green", "yellow", "orange", "red" };
7
8 public Spectrum(bool listFromUVtoIR)
9 {
10 _listFromUVtoIR = listFromUVtoIR;
11 }
12
13 public IEnumerator<string> GetEnumerator()
14 {
15 return _listFromUVtoIR
16 ? UVtoIR
17 : IRtoUV;
18 }
19
20 public IEnumerator<string> UVtoIR
21 {
22 get
23 {
24 for (int i = 0; i < colors.Length; i++)
25 yield return colors[i];
26 }
27 }
28
29 public IEnumerator<string> IRtoUV
30 {
31 get
32 {
33 for (int i = colors.Length - 1; i >= 0; i--)
34 yield return colors[i];
35 }
36 }
37 }
38
39 class Program
40 {
41 static void Main()
42 {
43 Spectrum startUV = new Spectrum(true);
44 Spectrum startIR = new Spectrum(false);
45
46 foreach (string color in startUV)
47 Console.Write($"{ color } ");
48 Console.WriteLine();
49
50 foreach (string color in startIR)
51 Console.Write($"{ color } ");
52 Console.WriteLine();
53 }
54 }
原创文章,作者:506227337,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/273101.html