一、几个基本概念的理解
问题一:为什么数组可以使用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
时间: 2024-10-26 01:37:09