1. 程式人生 > 其它 >在自己的物件裡實現IEnumerator和IEnumerable

在自己的物件裡實現IEnumerator和IEnumerable

轉載自:https://www.cnblogs.com/yplong/p/5286906.html

平時工作中我們經常用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 }
程式設計是個人愛好