迭代器模式
定义参考 wiki: Iterator pattern
迭代器模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可让外部代码透明地访问集合内部的数据。 ------- 节选自 《大话设计模式》P207
我们可以将迭代器模式抽离出几个重要组成部分:
1. 迭代器抽象类
2. 聚集抽象类
3. 具体迭代器类
4. 具体聚集类
1. 迭代器抽象类
1 public interface IEnumerator 2 { 3 bool MoveNext(); 4 5 Object Current { 6 get; 7 } 8 9 void Reset(); 10 }
reference: .NET IEnumerator
2. 聚集抽象类
1 public interface IEnumerable 2 { 3 IEnumerator GetEnumerator(); 4 }
reference: .NET IEnumerable
3. 具体迭代器类
通过查看.NET代码可以知道,在List、Dictionary类中都声明了具体的迭代器struct Enumerator,List中Enumerator代码如下:
1 [Serializable] 2 public struct Enumerator : IEnumerator<T>, 3 System.Collections.IEnumerator 4 { 5 private List<T> list; 6 private int index; 7 private int version; 8 private T current; 9 10 internal Enumerator(List<T> list) { 11 this.list = list; 12 index = 0; 13 version = list._version; 14 current = default(T); 15 } 16 17 public void Dispose() { 18 } 19 20 public bool MoveNext() { 21 22 List<T> localList = list; 23 24 if (version == localList._version && ((uint)index < (uint)localList._size)) 25 { 26 current = localList._items[index]; 27 index++; 28 return true; 29 } 30 return MoveNextRare(); 31 } 32 33 private bool MoveNextRare() 34 { 35 if (version != list._version) { 36 ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion); 37 } 38 39 index = list._size + 1; 40 current = default(T); 41 return false; 42 } 43 44 public T Current { 45 get { 46 return current; 47 } 48 } 49 50 Object System.Collections.IEnumerator.Current { 51 get { 52 if( index == 0 || index == list._size + 1) { 53 ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen); 54 } 55 return Current; 56 } 57 } 58 59 void System.Collections.IEnumerator.Reset() { 60 if (version != list._version) { 61 ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion); 62 } 63 64 index = 0; 65 current = default(T); 66 } 67 }
reference: .NET List Enumerator
4. 具体聚集类
同样以List为例,reference: .NET List
5. 利用 foreach 来遍历对象
foreach(int i in obj) {...}经过编译器转换将会变成如下:
var tmp = obj.GetEnumerator(); int i; while (tmp.MoveNext()) { i = tmp.Current; {...} // your code }
所以可以知道,只要我们实现了迭代器类和聚集类,那么就可以通过foreach来进行遍历了。
参考
1. How do foreach loops work in C#?
3. 详解C# 迭代器
4. .Net学习难点讨论系列11 - foreach与迭代器
时间: 2024-10-20 05:57:00