zoukankan      html  css  js  c++  java
  • 在自己的对象里实现IEnumerator和IEnumerable

    平时工作中我们经常用foreach来迭代一个集合。比如

    1 foreach (Student student in myClass)
    2 3        Console.WriteLine(student);
    4 5  

    基本所有的集合都能够foreach,但是必须要实现IEnumerable接口。IEnumerable接口很简单,就只有一个IEnumerator GetEnumerator() 方法。看这个方法的定义就知道,仅仅是公开了另一个接口IEnumerator。而IEnumerator才是真正的支持一个集合的迭代。IEnumerator有1个属性和2个方法。

    public object Current;

    public void Reset();

    public bool MoveNext();

    只允许读取集合的数据,而不允许修改。为了详细的讲解,我们来写一个简单的例子,就会一目了然。

    首先我们创建一个学生类Student如下:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 
     6 namespace IenumerableDemo
     7 {
     8     public class Student
     9     {
    10         #region 私有变量
    11 
    12         private readonly string _id;
    13         private string _firstname;
    14         private string _lastname;
    15 
    16         #endregion
    17         #region 属性
    18         public string ID { get { return _id; } }
    19 
    20         public string FirstName { get { return _firstname; } set { _firstname = value; } }
    21 
    22         public string LastName { get { return _lastname; } set { _lastname = value; } }
    23 
    24 
    25         #endregion
    26 
    27         #region 构造函数
    28 
    29         public Student(string id, string firstname, string lastname)
    30         {
    31             this._id = id;
    32 
    33             this._firstname = firstname;
    34 
    35             this._lastname = lastname;
    36         }
    37 
    38         #endregion
    39         #region  重写基类object方法
    40 
    41         public override string ToString()
    42         {
    43             return string.Format("{0} {1},ID:{2}", _firstname, _lastname, _id);
    44         }
    45 
    46         public override bool Equals(object obj)
    47         {
    48             if (obj == null) return false;
    49             if (Object.ReferenceEquals(this, obj)) return true;
    50             if (this.GetType() != obj.GetType()) return false;
    51 
    52             Student objstudent = (Student)obj;
    53             if (_id.Equals(objstudent._id)) return true;
    54 
    55             return false;
    56         }
    57 
    58         public override int GetHashCode()
    59         {
    60             return _id.GetHashCode();
    61         }
    62         #endregion
    63 
    64     }
    65 }
    66 
    67         

    接下来我们定义一个ClassList类来承载学生。让我们先忘记Ienmerable。这个类包含一个ArrayList字段_student,在构造函数中模拟3个学生。_student是私有的,不对外公开的。

     1 using System;
     2 using System.Collections;
     3 using System.Collections.Generic;
     4 using System.Linq;
     5 using System.Text;
     6 
     7 namespace IenumerableDemo
     8 {
     9     public class ClassList
    10     {
    11 
    12         #region private Members
    13 
    14         private readonly string _id;
    15 
    16         private ArrayList _students;
    17 
    18         #endregion
    19 
    20         #region Properties
    21         public string ID { get { return _id; } }
    22         #endregion
    23 
    24         #region Constructors
    25 
    26         public ClassList(string id)
    27         {
    28 
    29             this._id = id;
    30             _students = new ArrayList() { new Student("12345", "John", "Smith"), new Student("09876", "Jane", "Doe"), new Student("76403", "Bob", "Johnson") };
    31 
    32         }
    33 
    34         #endregion
    35 
    36  
    37     }
    38 }

    为了让对象支持foreach 迭代,ClassList类需要实现IEnumerable。因为我们的student是存在ArrayList对象里的,而ArrayList类已经实现了IEnumerable,我们就可以使用ArrayList类的Ienumerable。

    1        public IEnumerator GetEnumerator()
    2         {
    3 
    4             return (_students as IEnumerable).GetEnumerator();
    5 
    6         }

    最终的代码贴一下:

     1 using System;
     2 using System.Collections;
     3 using System.Collections.Generic;
     4 using System.Linq;
     5 using System.Text;
     6 
     7 namespace IenumerableDemo
     8 {
     9     public class ClassList:IEnumerable
    10     {
    11 
    12         #region private Members
    13 
    14         private readonly string _id;
    15 
    16         private ArrayList _students;
    17 
    18         #endregion
    19 
    20         #region Properties
    21         public string ID { get { return _id; } }
    22         #endregion
    23 
    24         #region Constructors
    25 
    26         public ClassList(string id)
    27         {
    28 
    29             this._id = id;
    30             _students = new ArrayList() { new Student("12345", "John", "Smith"), new Student("09876", "Jane", "Doe"), new Student("76403", "Bob", "Johnson") };
    31 
    32         }
    33 
    34         #endregion
    35 
    36         public IEnumerator GetEnumerator()
    37         {
    38 
    39             return (_students as IEnumerable).GetEnumerator();
    40 
    41         }
    42     }
    43 }

    然后我们调用看看使用ArrayList的Ienumerable效果:

     1 using System;
     2 using System.Collections;
     3 using System.Collections.Generic;
     4 using System.Linq;
     5 using System.Text;
     6 
     7 namespace IenumerableDemo
     8 {
     9     class Program
    10     {
    11         static void Main(string[] args)
    12         {
    13             ClassList myClass = new ClassList("History 204");
    14 
    15 
    16             foreach (Student student in myClass)
    17 
    18                 Console.WriteLine(student);
    19 
    20 
    21             Console.ReadLine();
    22         }
    23 
    24 
    25     }
    26 
    27 
    28 }

    看来还是实现了效果。那么接下来我们看看自定义实现IEnumerable。实现IEnumerable其实只要实现IEnumerator接口就可以了。

    我们创建我们自己的一个自定义类ClassEnumerator 来实现IEnumerator来完成和上面相同的结果。这个类基本上就只是通过_students的索引来进行迭代,Reset()方法就是把索引设置为-1.Current属性来获取当前的student,MoveNext()来跳到Current的下一个数据,并返回一个boolean来表示是否到了集合最后。

     1 using System;
     2 using System.Collections;
     3 using System.Collections.Generic;
     4 using System.Linq;
     5 using System.Text;
     6 
     7 namespace IenumerableDemo
     8 {
     9     public class ClassEnumerator : IEnumerator
    10     {
    11 
    12         private ClassList _classList;
    13 
    14         private int _index;
    15 
    16         public ClassEnumerator(ClassList classList)
    17         {
    18             this._classList = classList;
    19 
    20             _index = -1;
    21         }
    22 
    23         #region IEnumerator Members
    24 
    25         public void Reset()
    26         {
    27             this._index = -1;
    28         }
    29 
    30         public object Current
    31         {
    32             get { return _classList.Students[_index]; }
    33         }
    34 
    35         public bool MoveNext()
    36         {
    37             _index++;
    38             if (_index >= _classList.Students.Count)
    39                 return false;
    40             else
    41                 return true;
    42 
    43         }
    44         #endregion
    45 
    46     }
    47 }

    最后修改我们的ClassLst类:

     1 using System;
     2 using System.Collections;
     3 using System.Collections.Generic;
     4 using System.Linq;
     5 using System.Text;
     6 
     7 namespace IenumerableDemo
     8 {
     9     public class ClassList : IEnumerable
    10     {
    11 
    12         #region private Members
    13 
    14         private readonly string _id;
    15 
    16         private ArrayList _students;
    17 
    18         #endregion
    19 
    20         #region Properties
    21         public string ID { get { return _id; } }
    22 
    23         public ArrayList Students { get { return _students; } }
    24         #endregion
    25 
    26         #region Constructors
    27 
    28         public ClassList(string id)
    29         {
    30 
    31             this._id = id;
    32             _students = new ArrayList() { new Student("12345", "John", "Smith"), new Student("09876", "Jane", "Doe"), new Student("76403", "Bob", "Johnson") };
    33 
    34         }
    35 
    36         #endregion
    37 
    38         public IEnumerator GetEnumerator()
    39         {
    40 
    41             return (IEnumerator)new ClassEnumerator(this);
    42 
    43         }
    44     }
    45 }

    可已看到还是相当简单的。运行结果和上面是一样的。

     下来看看 foreach怎么工作。

    其实foreach只是语法糖,最终会被CLR翻译成

    1             IEnumerator enumerator = myClass.GetEnumerator();
    2             while (enumerator.MoveNext())
    3             {
    4                 Console.WriteLine((Student)enumerator.Current);
    5 
    6             }

    我们可以把foreach 换成这样试一下,结果是一样滴。

     1 using System;
     2 using System.Collections;
     3 using System.Collections.Generic;
     4 using System.Linq;
     5 using System.Text;
     6 
     7 namespace IenumerableDemo
     8 {
     9     class Program
    10     {
    11         static void Main(string[] args)
    12         {
    13             ClassList myClass = new ClassList("History 204");
    14 
    15 
    16             //foreach (Student student in myClass)
    17 
    18             //    Console.WriteLine(student);
    19 
    20 
    21             IEnumerator enumerator = myClass.GetEnumerator();
    22             while (enumerator.MoveNext())
    23             {
    24                 Console.WriteLine((Student)enumerator.Current);
    25 
    26             }
    27 
    28             Console.ReadLine();
    29         }
    30 
    31 
    32     }
    33 
    34 
    35 }
  • 相关阅读:
    React 中使用 pdf.js 将 pdf 转换成图片
    html2pdf 无法导出 html 中 img 图片的解决方法
    js-xlsx 实现前端 Excel 导出(支持多 sheet)
    React 项目引入 Dva
    项目构建分析和 webpack 优化实践
    《写给大家看的设计书》读书笔记
    2019年六月前端面试经验总结
    UITableView .grouped 类型去除顶部间距
    Ant Design Upload 组件上传文件到云服务器
    家庭动物园下载链接
  • 原文地址:https://www.cnblogs.com/yplong/p/5286906.html
Copyright © 2011-2022 走看看