由 Foreach关键字引出一个设计模式
时间有限,用代码和注释来表达自己的理解
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace LinqTrain { /// <summary> /// 一个类要想能被foreach,可以实现这个接口,是一种方式,但不是必须,本质是必须要有一个返回IEnumerator的方法。 /// 而实现 IEnumerable,就必须实现接口方法 IEnumerator GetEnumerator() /// 也就是说,一个类要想能被foreach,就是要配套实现一个枚举器,把自己里面的列表内容传递给枚举器,比如这里实现的 /// StudentEnumerator这个枚举器。 /// </summary> public class Students : IEnumerable { string[] _studentList = new string[] {"AAAA","BBBB","CCCC","DDDD","FFFF" }; /// <summary> /// 这是个什么东西?获取当前元素,能否下一步, /// </summary> /// <returns></returns> public IEnumerator GetEnumerator() { //第一种,自己实现枚举器 //return new StudentEnumerator(_studentList); //第二种方式,yield使用,一个关键字帮我们实现了枚举器 //好处:不用把数据一次性加载到内存,细水长流,"按需供给"。 //yield每次返回一个数据给外面,那么外面再次调用枚举器的时候,怎么记从那个位置给数据? //其实 yield 里面在枚举器里面还实现了一个状态机,状态机里面有变量值记录了已经迭代的位置 //这里谈的foreach 就是设计模式里面的迭代器模式,本质就是把怎么筛选数据的算法和数据本身分离 for (int i = 0; i < _studentList.Length; i++) { yield return _studentList[i]; } } } public class StudentEnumerator : IEnumerator { string[] list; private int index = -1; public StudentEnumerator(string [] array) { list = array; } public object Current => list[index]; public bool MoveNext() { if (index<list.Count()-1) { index ++; return true; } else { return false; } } public void Reset() { this.index = -1; } } }