由 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;
        }
    }
}

 

posted @ 2022-07-19 11:20  LearningAlbum  阅读(40)  评论(0)    收藏  举报