一、幾個基本概念的理解
問題一:為什么數組可以使用foreach輸出各元素
答:數組是可枚舉類型,它實現了一個枚舉器(enumerator)對象;枚舉器知道各元素的次序並跟蹤它們的位置,然后返回請求的當前項
問題二:不用foreach能不能遍歷各元素
問題三:什么是可枚舉類
答:可枚舉類是指實現了IEnumerable接口的類;IEnumerable接口只有一個成員GetEnumerator方法,它返回對象的枚舉器
問題四:什么是枚舉器
答:實現了IEnumerator接口的枚舉器包含三個函數成員:Current,MoveNext,Reset
Current是只讀屬性,它返回object類型的引用;
MoveNext是把枚舉器位置前進到集合的下一項的方法,它返回布爾值,指示新的位置是否有效位置還是已經超過了序列的尾部;
Reset是把位置重置為原始狀態的方法;
二、下面代碼展示了一個可枚舉類的完整示例

1 namespace ConsoleApplication4 2 { 3 /// <summary> 4 /// 自定義一個枚舉對象 5 /// </summary> 6 class ColorEnumerator : IEnumerator 7 { 8 private string[] _colors; 9 private int _position = -1; 10 11 public ColorEnumerator(string[] arr) 12 { 13 _colors = arr; 14 for (int i = 0; i < arr.Length; i++) 15 { 16 _colors[i] = arr[i]; 17 } 18 } 19 public object Current 20 { 21 get 22 { 23 if (_position == -1) 24 { 25 throw new InvalidOperationException(); 26 } 27 if (_position >= _colors.Length) 28 { 29 throw new InvalidOperationException(); 30 } 31 return _colors[_position]; 32 } 33 } 34 35 public bool MoveNext() 36 { 37 if (_position < _colors.Length - 1) 38 { 39 _position++; 40 return true; 41 } 42 else 43 { 44 return false; 45 } 46 } 47 48 public void Reset() 49 { 50 _position = -1; 51 } 52 } 53 54 /// <summary> 55 /// 創建一個實現IEnumerable接口的枚舉類 56 /// </summary> 57 class Spectrum : IEnumerable 58 { 59 private string[] Colors = { "red", "yellow", "blue" }; 60 public IEnumerator GetEnumerator() 61 { 62 return new ColorEnumerator(Colors); 63 } 64 } 65 66 class Program 67 { 68 static void Main(string[] args) 69 { 70 Spectrum spectrum = new Spectrum(); 71 foreach (string color in spectrum) 72 { 73 Console.WriteLine(color); 74 } 75 Console.ReadKey(); 76 } 77 } 78 } 79
三、泛型枚舉接口
IEnumerable<T>接口的GetEnumerator方法返回實現IEnumerator<T>的枚舉類的實例;
實現IEnumerator<T>的類實現了Current屬性,它返回實際類型的對象,而不是object基類的引用;
所以非泛型接口的實現不是類型安全的,因為還需要轉換為實際類型。
四、迭代器
1.使用迭代器來創建枚舉器

1 namespace ConsoleApplication5 2 { 3 class MyClass 4 { 5 /// <summary> 6 /// 獲取一個迭代器 7 /// </summary> 8 /// <returns></returns> 9 public IEnumerator<string> GetEnumerator() 10 { 11 return ColorEnumerator(); 12 } 13 /// <summary> 14 /// 迭代器 15 /// </summary> 16 /// <returns></returns> 17 public IEnumerator<string> ColorEnumerator() 18 { 19 yield return "red"; 20 yield return "yellow"; 21 yield return "blue"; 22 } 23 } 24 class Program 25 { 26 static void Main(string[] args) 27 { 28 MyClass mc = new MyClass(); 29 foreach (string color in mc) 30 { 31 Console.WriteLine(color); 32 } 33 Console.ReadKey(); 34 } 35 } 36 }
2.使用迭代器來創建枚舉類型

1 namespace ConsoleApplication6 2 { 3 class MyClass 4 { 5 public IEnumerator<string> GetEnumerator() 6 { 7 //獲取可枚舉類型 8 IEnumerable<string> enumerable = ColorEnumerable(); 9 //獲取枚舉器 10 return ColorEnumerable().GetEnumerator(); 11 } 12 13 public IEnumerable<string> ColorEnumerable() 14 { 15 yield return "red"; 16 yield return "yellow"; 17 yield return "blue"; 18 } 19 } 20 class Program 21 { 22 static void Main(string[] args) 23 { 24 MyClass mc = new MyClass(); 25 //使用類對象 26 foreach (string color in mc) 27 { 28 Console.WriteLine(color); 29 } 30 Console.WriteLine("-----------------------"); 31 //使用類枚舉器的方法 32 foreach (string color in mc.ColorEnumerable()) 33 { 34 Console.WriteLine(color); 35 } 36 Console.ReadKey(); 37 } 38 } 39 }
3.產生多個可迭代類型

1 namespace ConsoleApplication7 2 { 3 class MyClass 4 { 5 private string[] Colors = { "red", "yellow", "blue" }; 6 //順序 7 public IEnumerable<string> ColorOrder() 8 { 9 for (int i = 0; i < Colors.Length; i++) 10 { 11 yield return Colors[i]; 12 } 13 } 14 //逆序 15 public IEnumerable<string> ColorReversed() 16 { 17 for (int i = Colors.Length - 1; i >= 0; i--) 18 { 19 yield return Colors[i]; 20 } 21 } 22 } 23 class Program 24 { 25 static void Main(string[] args) 26 { 27 MyClass mc = new MyClass(); 28 foreach (string color in mc.ColorOrder()) 29 { 30 Console.WriteLine(color); 31 } 32 Console.WriteLine("------------------"); 33 foreach (string color in mc.ColorReversed()) 34 { 35 Console.WriteLine(color); 36 } 37 Console.ReadKey(); 38 } 39 } 40 } 41