public interface IEnumerable { //返回一個實現了IEnumerator接口的對象 //個人理解:實現該接口的類,用其下哪一個可枚舉的元素實現該方法那麼當該類被枚舉時,將獲得該類下的某個可枚舉元素的元素 IEnumerator GetEnumerator(); }
public class TestEnumerable : IEnumerable { //可枚舉元素 private Student[] _students; public TestEnumerable(Student[] list) { _students = list; } public IEnumerator GetEnumerator() { //當TestEnumerator被枚舉時,將獲得_students的元素 return _students.GetEnumerator(); } } public class Student { public string ID { get; set; } public string Name { get; set; } public Student(string id, string name) { ID = id; Name = name; } }
調用代碼:express
public static void Main() { Student[] students = new Student[3] { new Student("ID1", "Name1"), new Student("ID2", "Name2"), new Student("ID3", "Name3"), }; TestEnumerable testEnumerable = new TestEnumerable(students); foreach (Student s in testEnumerable) { Console.WriteLine("ID:{0};Name:{1}", s.ID, s.Name); } }
如上文所說, TestEnumerable類用foreach枚舉,獲得的每個對象就是上文提到的「能夠枚舉的元素(Student[])的每個對象」 。ide
public interface IEnumerator { //獲取集合中的當前元素 object Current{get;set;} //枚舉數推動到集合的下一個元素,當存在下一個對象時返回true,不存在時返回false bool MoveNext(); //枚舉數設置爲其初始位置,該位置位於集合中第一個元素以前 void Reset(); }
public class TestEnumerator : IEnumerator { //指針,指向枚舉元素 (爲何這裏是-1,由於在MoveNext()中,_position++) private int _position = -1; private Student[] _students; public TestEnumerator() { } public TestEnumerator(Student[] list) { _students = list; } /// <summary> /// 獲取當前元素 /// </summary> public object Current { get { return _students[_position]; } } /// <summary> /// 移動到下一個元素 /// </summary> /// <returns>成功移動到下一個元素返回:true;失敗返回:false</returns> public bool MoveNext() { _position++; return _position < _students.Length; } /// <summary> /// 重置到第一個元素 /// </summary> public void Reset() { _position = -1; } } public class TestEnumerable2 : IEnumerable { private Student[] _students; public TestEnumerable2(Student[] list) { _students = list; } public IEnumerator GetEnumerator() { return new TestEnumerator(_students); } }
調用代碼:函數
public static void Main() { Student[] students = new Student[3] { new Student("ID1", "Name1"), new Student("ID2", "Name2"), new Student("ID3", "Name3"), }; TestEnumerable2 testEnumerator = new TestEnumerable2(students); foreach (Student s in testEnumerator) { Console.WriteLine("ID:{0};Name:{1}", s.ID, s.Name); } }
IEnumerable接口與IEnumerator接口算介紹完畢了。測試
你們看IEnumerator接口的實現,就是實現一個屬性,兩個調整枚舉點的方法。若是能有一種方式,能自動幫咱們完成IEnumerator接口的實現,那麼將方便不少。this
在.NET Framework 3.5中有了yield,這個關鍵字能夠幫咱們自動生成實現IEnumerator的類。spa
下面,咱們先來看一下MSDN上的介紹指針
1.foreach 循環的每次迭代都會調用迭代器方法
2.迭代器方法運行到 yield return
語句時,會返回一個expression表達式並保留當前在代碼中的位置
3.當下次調用迭代器函數時執行從該位置從新啓動code
其實msdn這裏解釋的有點囉嗦了。簡單點說,就是迭代器運行到yield return語句時,將自動作兩件事。對象
1.記錄當前訪問的位置
2.當下次調用迭代器函數時執行從該位置從新啓動:MoveNext()blog
下面咱們來看一段實例代碼:
public class TestEnumerable3 : IEnumerable { private Student[] _students; public TestEnumerable3(Student[] list) { _students = list; } //實現與以前有不一樣 public IEnumerator GetEnumerator() { //迭代集合 foreach (Student stu in _students) { //返回當前元素,剩下的就交給yield了,它會幫咱們生成一個實現了接口IEnumerator的類 //來幫咱們記住當前訪問到哪一個元素。 yield return stu; } } }
下面我貼出一段GetEnumerator()方法的IL代碼,來證實yield return 幫咱們自動生成了一個實現了IEnumerator接口的類
.method public final hidebysig newslot virtual instance class [mscorlib]System.Collections.IEnumerator GetEnumerator () cil managed { // Method begins at RVA 0x228c // Code size 20 (0x14) .maxstack 2 .locals init ( [0] class TestBlog.TestEnumerable3/'<GetEnumerator>d__0', //這句最重要,初始化了一個實現System.Collections.IEnumerator的class,存儲在索引1的位置 [1] class [mscorlib]System.Collections.IEnumerator ) IL_0000: ldc.i4.0 IL_0001: newobj instance void TestBlog.TestEnumerable3/'<GetEnumerator>d__0'::.ctor(int32) IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: ldarg.0 IL_0009: stfld class TestBlog.TestEnumerable3 TestBlog.TestEnumerable3/'<GetEnumerator>d__0'::'<>4__this' IL_000e: ldloc.0 IL_000f: stloc.1 IL_0010: br.s IL_0012 IL_0012: ldloc.1 IL_0013: ret } // end of method TestEnumerable3::GetEnumerator
最後就是調用代碼:
static void Main(string[] args) { Student[] students = new Student[3] { new Student("ID1", "Name1"), new Student("ID2", "Name2"), new Student("ID3", "Name3"), }; TestEnumerable3 testEnumerable3 = new TestEnumerable3(students); foreach (Student s in testEnumerable3) { Console.WriteLine("ID:{0};Name:{1}", s.ID, s.Name); } }
/// <summary> /// IEnumerable構建迭代方法 /// <param name="_students">排序集合</param> /// <param name="direction">排序順序(true:順序;false:倒序)</param> public IEnumerable SortStudents(Student[] _students,bool direction) { if (direction) { foreach (Student stu in _students) { yield return stu; } } else { for (int i = _students.Length; i != 0; i--) { yield return _students[i - 1]; } } }
細心的朋友必定發現了。這個方法的返回類型爲IEnumerable,而不像實現接口IEnumerable的GetEnumerator()方法返回類型是IEnumerator。這就是IEnumerable構建迭代方法須要注意的地方。
下面是測試代碼:
static void Main(string[] args) { Student[] students = new Student[3] { new Student("ID1", "Name1"), new Student("ID2", "Name2"), new Student("ID3", "Name3"), };
foreach (Student s in SortStudents(students,false)) { Console.WriteLine("ID:{0};Name:{1}", s.ID, s.Name); } }
感謝你們的耐心閱讀。