IEnumerable和IEnumerator类型:
IEnumerable只是一个接口用于foreach迭代器遍历之前用一个GetEnumerator获取一个IEnumerator对象且只获取一次,IEnumerator才是真正的迭代器对象,IEnumerator有Current属性,MoveNex()t和Reset()方法。所以如果是系统默认类型的IEnumerable<T>和IEnumerator<T>那么就不需要自定义这两个类了,反之则要定义。这个是一个迭代器模式,是C#广泛使用泛型和面向接口编程的经典体现。
所以要声明支持foreach类型的自定义枚举集合类,那么需要声明数组默认继承IEnumerable需要实现IEnumerator<T> GetEnumerator()函数,再定义自己的IEnumerator<T>类,如果是默认类型的IEnumerator<T>就不需要了,这里只是用了迭代器设计模式和面向接口的编程思想,例如:
来自:https://msdn.microsoft.com/zh-cn/library/system.collections.ienumerable.getenumerator%28v=vs.110%29.aspx 的实例
using System; using System.Collections; // Simple business object. public class Person { public Person(string fName, string lName) { this.firstName = fName; this.lastName = lName; } public string firstName; public string lastName; } // Collection of Person objects. This class // implements IEnumerable so that it can be used // with ForEach syntax. public class People : IEnumerable { private Person[] _people; public People(Person[] pArray) { _people = new Person[pArray.Length]; for (int i = 0; i < pArray.Length; i++) { _people[i] = pArray[i]; } } // Implementation for the GetEnumerator method. // People继承自IEnumerable,用于该类获取真正的迭代器 IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)GetEnumerator(); } // PeopleEnum为真正的迭代器,因为PeopleEnum是自定义了,默认不支持 // 所以需要为PeopleEnum迭代器定义Current属性,和MoveNext,Reset方法。 public PeopleEnum GetEnumerator() { return new PeopleEnum(_people); } } // When you implement IEnumerable, you must also implement IEnumerator. public class PeopleEnum : IEnumerator { public Person[] _people; // Enumerators are positioned before the first element // until the first MoveNext() call. // 构造时候会初始化这些 int position = -1; public PeopleEnum(Person[] list) { _people = list; } // MoveNext为false就不会继续移动了,除非reset或重新生成一个 public bool MoveNext() { position++; return (position < _people.Length); } public void Reset() { position = -1; } // 真正的迭代器要求定义的属性,会调用Person Current object IEnumerator.Current { get { return Current; } } // 当前的获取Current的值 public Person Current { get { try { return _people[position]; } catch (IndexOutOfRangeException) { throw new InvalidOperationException(); } } } } class App { static void Main() { Person[] peopleArray = new Person[3] { new Person("John", "Smith"), new Person("Jim", "Johnson"), new Person("Sue", "Rabon"), }; // 自定义的IEnumerable类型 People peopleList = new People(peopleArray); // 会得到自定义的PeopleEnum,接着进行循环遍历 foreach (Person p in peopleList) Console.WriteLine(p.firstName + " " + p.lastName); } } /* This code produces output similar to the following: * * John Smith * Jim Johnson * Sue Rabon * */
yield语句也是一个迭代块,必须声明返回值类型为IEnumerable、IEnumerable<T>、IEnumerator<T>、IEnumerator类型,如果非内置类型的IEnumerable<T>还要定义IEnumerator<T> GetEnumerator(), 如果IEnumerator是非内置类型的那么需要定义真正迭代器的Current属性,和MoveNext,Reset方法。