在自己的对象里实现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 }

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

时间: 2024-08-04 09:17:53

在自己的对象里实现IEnumerator和IEnumerable的相关文章

对象里的handleEvent

最近看swipe.js源码看到handleEvent这个属性.查了一下资料才知道: 使用 addEventListener 可以绑定事件,并传入回调函数. Mozilla 0.9.1 和 Netscape 6.1 之后的版本不但支持传递函数引用,也都允许直接把拥有 handleEvent 方法的对象作为 addEventListener 方法的第二参数. 看例子1, 最简单的实现方式 html <div id="box" style="background:#ccc;w

【ThinkingInC++】46、特定的数据成员可以在一个const对象里被改变

/** * 书本:[ThinkingInC++] * 功能:声明关键字mutable,指定一个特定的数据成员可以在一个const对象里被改变 * 时间:2014年9月11日07:47:07 * 作者:cutter_point */ class Z { int i; mutable int j; public: Z(); void f() const; }; Z::Z():i(0), j(0) {} void Z::f() const { //! i++; //没有声明是mutable,所以没法修

js如何检测一个属性是否在json对象里

1, in运算符2, hasOwnProperty()3, != undefined //检测o对象里是否有属性a var o={a:1,b:2,c:3}; console.log("a" in o); console.log(o.hasOwnProperty("a")); console.log(o.a != undefined);

JavaScript怎么把对象里的数据整合进另外一个数组里

https://blog.csdn.net/qq_26222859/article/details/70331833 var json1 = [ {"guoshui":[ 300000, 500000, 600000, 800000, 1000000, 1200000, 1400000, 1600000, 1800000, 1600000, 1400000, 1200000 ]}, {"dishui":[ 1100000, 1200100, 1300000, 110

flask中的CBV , flask-session在redis中存储session , WTForms数据验证 , 偏函数 , 对象里的一些小知识

flask中的CBV , flask-session在redis中存储session , WTForms数据验证 , 偏函数 , 对象里的一些小知识 flask中的CBV写法 后端代码 # 导入views from flask import Flask, render_template, views, request app = Flask(__name__) # CBV写法 class Login(views.MethodView):       # 定义一个类,不用装饰器,继承了Method

当改变数组的某一个对象里的元素的时候,为什么其他对象里的元素也发生改变了

当运用多层循环的时候,会出现一种情况,就是当想改变数组的某一个对象里的元素的时候,其他对象里的元素页跟着发生了改变.根据条件已经定位到了某一个对象,但是改变之后发现,其他的还是也都改变了. 原因就是: 数组是引用对象,数组变量存储在栈,元素数据存储在堆中,将数组赋值不同的对象,所以赋值对象都指向堆同一个数据,因此改变其中一个数组对象里的元素,其他对象里的元素也会发生改变 解决方法: var arr = JSON.parse(JSON.stringify(array)); 原文地址:https:/

C# IEnumerator与 IEnumerable

1. 接口的使用 (1)  首先定义接口 public interface IBattleMapManager : { Stages CurrentStage { get; } event EventHandler<BeginFightEventArgs> EnterFight; } (2) 用定义实现类- 实现接口 public class BattleMapManager : IBattleMapManager, IDisposable { public Stages CurrentSta

IEnumerator和IEnumerable接口

枚举器和可枚举类型 前面我们已经知道了使用foreach语句可以遍历数组中的元素.但是为什么那么做呢? 原因是数组按需提供了一个叫做枚举器的对象.枚举器可以依次返回请求数组中的元素. 枚举器知道项的次序并且跟踪它所在序列中的位置,然后返回请求的当前项. 获取一个对象枚举器的方法是调用对象的GetEnumerator方法.实现GetEnumerator方法的类型叫做可枚举类型. 数组是可枚举类型. IEnumerator接口 实现了IEnumerator接口的枚举器包含3个函数成员:Current

IEnumerator和IEnumerable详解

IEnumerator和IEnumerable 从名字常来看,IEnumerator是枚举器的意思,IEnumerable是可枚举的意思. 了解了两个接口代表的含义后,接着看源码: IEnumerator: public interface IEnumerator { // Interfaces are not serializable // Advances the enumerator to the next element of the enumeration and // returns