• C#基础—迭代器(Iterator)


    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 中再谈,欢迎交流!

  • 相关阅读:
    【开源】我和 JAP(JA Plus) 的故事
    justauth-spring-boot-starter V1.3.5 发布成功
    JustAuth 1.15.9 版发布,支持飞书、喜马拉雅、企业微信网页登录
    详细介绍如何自研一款"博客搬家"功能
    推荐一款自研的Java版开源博客系统OneBlog
    JavaScript常用方法
    Markdown 语法学习
    Sublime Text常用设置之个人配置
    webStorm常用设置之过滤文件夹
    HTTP详解
  • 原文地址:https://www.cnblogs.com/ydchw/p/3735634.html
Copyright © 2020-2023  润新知