平時工做中咱們常常用foreach來迭代一個集合。好比web
1 foreach (Student student in myClass) 2 { 3 Console.WriteLine(student); 4 } 5
基本全部的集合都可以foreach,可是必需要實現IEnumerable接口。IEnumerable接口很簡單,就只有一個IEnumerator GetEnumerator() 方法。看這個方法的定義就知道,僅僅是公開了另外一個接口IEnumerator。而IEnumerator纔是真正的支持一個集合的迭代。IEnumerator有1個屬性和2個方法。ide
public object Current; 函數
public void Reset();this
public bool MoveNext();spa
只容許讀取集合的數據,而不容許修改。爲了詳細的講解,咱們來寫一個簡單的例子,就會一目瞭然。翻譯
首先咱們建立一個學生類Student以下:code
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是私有的,不對外公開的。orm
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 }
最終的代碼貼一下:blog
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 }