1、引入迭代器
记得以前经常做到一些面试题,是关于要实现迭代器必须实现什么接口?其实,在C# 1.0里我们就经常用到foreach了,所以,只要支持foreach,那么这个类型就可以使用foreach
去遍历。那如何才能支持foreach 呢?
其实,答案都知道,要实现IEnumerable 或 IEnumerable<T>、IEnumerator 接口,因为foreach
需要迭代器的支持,而IEnumerable 接口中含有返回迭代器的 GetEnumerator 方法,对此,可以查看下MSDN 对 IEnumerable
的定义。所以,我们只要实现这个方法就可以使用foreach 来遍历我们需要的类型。
2、迭代器的使用
什么是迭代器?
简单的理解就是集合中的某个位置。我们先写个小Demo来认识下如何去实现一个自定义的迭代器:
1 //1.首先定义一个需要实现foreach遍历的对象,我们假设为要遍历一群人
3 class Person
5 {
7 public string FirstName;
11 public string LastName;
15 public Person(string firstName, string lastName)
17 {
19 this.FirstName = firstName;
21 this.LastName = lastName;
23 }
25 }
26
29 //2. 定义一个那个我们要遍历的一群人集合,我们把这个类型叫:PersonList
31 class PersonList : IEnumerable
33 {
35 //其实操作的是Person的数组
37 private Person[] _personList;
41 public PersonList(Person[] PersonList)
43 {
45 this._personList = PersonList;
47 }
48
51 /// <summary>
53 ///用来遍历PersionList类的索引器,类似类数组
55 /// </summary>
57 /// <param name="index"></param>
59 /// <returns></returns>
61 public Person this[int index]
63 {
65 get
67 {
69 return this._personList[index];
71 }
73 }
74
77 /// <summary>
79 ///一般集合也都有一个Count,我们也实现下
81 /// </summary>
83 public int Count
85 {
87 get
89 {
91 return this._personList.Length;
93 }
95 }
96
99 /// <summary>
101 ///这个是返回迭代器的方法,必须要实现的
103 /// </summary>
105 /// <returns></returns>
107 public IEnumerator GetEnumerator()
109 {
111 return (new PersonIterator(this)); //把当前自定义的集合传给迭代器进行遍历功能的实现,并返回迭代器对象
113 }
115 }
116
119 //3.定义一个自定义的迭代器,我们假设叫 PersonIterator,实现迭代器需要实现 System.Collection.IEnumerator 接口
121 class PersonIterator : IEnumerator
123 {
125 //要遍历的自定义对象集合,传入迭代器进行遍历
127 private readonly PersonList _personList;
131 //当前位置的索引
133 private int _position = -1;
134
137 public PersonIterator(PersonList personList)
139 {
141 this._personList = personList;
143 }
144
147 #region自定义迭代器必须要实现的IEnumerator中的几个方法和属性
151 public object Current
153 {
155 get
157 {
159 try
161 {
163 return this._personList[this._position];
165 }
167 catch(IndexOutOfRangeException)
169 {
171 throw new IndexOutOfRangeException();
173 }
175 }
177 }
178
181 public bool MoveNext()
183 {
185 this._position++;
187 return (this._position < this._personList.Count);
189 }
190
193 public void Reset()
195 {
197 this._position = -1;
199 }
203 #endregion
207 }
208
209
210
211 class Program
213 {
215 static void Main(string[] args)
217 {
219 Person[] personArray = new Person[2]
221 {
223 new Person("三", "张"),
225 new Person("四", "李")
227 };
231 //测试
233 PersonList pList = new PersonList(personArray);
235 foreach (Person p in pList)
237 {
239 Console.WriteLine("遍历的姓名: {0} {1}", p.FirstName, p.LastName);
241 }
242
245 Console.Read();
247 }
249 }
程序输出:
遍历的姓名:三 张
遍历的姓名:四 李
至此,我们在梳理下实现的步骤:
(1).定义要遍历的对象 Person
(2).定义要遍历的对象集合类 PersonList 实现 IEnumerable
接口,主要实现 GetEnumerator()方法,以便于返回一个迭代器对象。
(3).定义一个自定义的迭代器类 PersonIterator 实现
IEnumerator 接口,主要实现该接口中定义的方法和属性。
整个迭代器的实现过程略微显得复杂,如果每次都这样实现,的确感觉不太理想,因此C# 2.0
为我们提供了语法糖:yield return。让我们来看看实现的过程有哪些简化的呢?由于篇幅原因,我只提供了修改的地方:
1 ///// <summary>
2 ///// 这个是返回迭代器的方法,必须要实现的
3 ///// </summary>
4 ///// <returns></returns>
5 //public IEnumerator GetEnumerator()
6 //{
7 // return (new PersonIterator(this)); //把当前自定义的集合传给迭代器进行遍历功能的实现,并返回迭代器对象
8 //}
9
10
11 /// <summary>
12 ///这个是返回迭代器的方法,必须要实现的, C# 2.0 的yield return
13 /// </summary>
14 /// <returns></returns>
15 public IEnumerator GetEnumerator()
16 {
17 for (var i = 0; i < this._personList.Length; i++)
18 {
19 yield return this._personList[i];
20 }
22 }
这样我们就省去了第三步去实现IEnumerator来构造一个迭代器类,但是编译器的工作还是不会少的,当编译器看到
yield return 时会自动为我们实现IEnumerator 接口,有兴趣的同仁可以查看下最后编译后的代码,在此不再敖述。
3、迭代器的执行过程
对于迭代器的执行过程,大家可以调试测试,这里直接引用下园子里大神的图片做个演示了:
至此,迭代器先谈这么多了,至于迭代器的延迟计算,我们到Linq 中再谈,欢迎交流!
C#基础—迭代器(Iterator),布布扣,bubuko.com