IEnumerable 接口
公开枚举数,该枚举数支持在非泛型集合上进行简单迭代。重复操作。
迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。每一次对过程的重复称为一次"迭代",而每一次迭代得到的结果会作为下一次迭代的初始值。
C#中的IEnumerable简介及简单实现实例
namespace ConsoleApplication1 { class Program { static void Main(string[] args) { charlist mycharlist = new charlist("hello world"); foreach (var c in mycharlist) { Console.Write(c); } Console.ReadLine(); } } class charlist : IEnumerable { public string TargetStr { get; set; } public charlist(string str) { this.TargetStr = str; } public IEnumerator GetEnumerator() { return new CharIterator(this.TargetStr); } } class CharIterator : IEnumerator //迭代器的实现 { public string TargetStr { get; set; } public int position { get; set; } //存储当前的迭代位置 public CharIterator(string targetStr) { this.TargetStr = targetStr; this.position = this.TargetStr.Length; } public object Current { //当前迭代位置的元素 get { if (this.position == -1 || this.position == this.TargetStr.Length) { throw new InvalidOperationException(); } return this.TargetStr[this.position]; } } public bool MoveNext() { //更新迭代位置,并且查看下一个迭代位置是不是有效的。 if (this.position != -1) { this.position--; } return this.position > -1; } public void Reset() { this.position = this.TargetStr.Length; } } }
代码首先执行到foreach语句的charList处获得迭代器CharIterator的实例,然后代码执行到in会调用迭代器的MoveNext方法,最后变量c会得到迭代器Current属性的值;前面的步骤结束后,会开始一轮新的循环,调用MoveNext方法,获取Current属性的值。
要实现一个迭代器就要实现IEnumerator接口,然后实现IEnumerator接口中的MoveNext、Reset方法和Current属性。
C#如何实现自定义集合的IEnumerable 和 IEnumerator 接口并使用foreach访问自定义集
static void Main(string[] args) { int[] array = new int[] { 5,4,3,2,1}; foreach (int i in array) Console.WriteLine("Number:"+i); Console.ReadKey(); } /** * -------------执行结果------------- * Number:5 * Number:4 * Number:3 * Number:2 * Number:1 * -------------执行结果------------- */
问题:为什么使用foreach可以遍历出数组中的所有元素呢?
原因:数组是可枚举类型,它可以按需提供枚举数,枚举数可以依次返回请求的数组的元素。而foreach结构被设计用来和可枚举类型一起使用,只要给foreach的遍历对象是可枚举类型,则她就会执行如下行为:
因为数组是可枚举类型,所以我就使用使用IEnumerator接口来实现枚举数以模仿foreach的循环遍历
static void Main(string[] args) { int[] array = new int[] { 5,4,3,2,1}; IEnumerator ie = array.GetEnumerator();//获取枚举数 while (ie.MoveNext())//移动下一项 { //最初,枚举数定位在集合中第一个元素前,在此位置上,Current 属性未定义 //因此,在读取 Current 的值之前,必须调用 MoveNext 方法将枚举数提前到集合的第一个元素 int i = (int)ie.Current;//获取当前项 Console.WriteLine("Number:" + i); } } /** * -------------执行结果------------- * Number:5 * Number:4 * Number:3 * Number:2 * Number:1 * -------------执行结果------------- */
实现IEnumerable 和 IEnumerator 接口
以下示例演示如何实现自定义集合的IEnumerable 和 IEnumerator 接口,在此示例中,没有显式调用这些接口的成员,但实现了它们,以便支持使用 foreach循环访问该集合
要点:
示意图:
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication1 { // 实现IEnumerator接口 public class PersonIEnumerator : IEnumerator { string[] Person; int position = -1; public PersonIEnumerator(string[] thePersons) { Person = new string[thePersons.Length]; for (int i = 0; i < thePersons.Length; i++) { Person[i] = thePersons[i]; } } //IEnumerator接口的特性1 public object Current { get { return Person[position]; } } //IEnumerator接口的特性2 public bool MoveNext() { if (position < Person.Length - 1) { position++; return true; } else return false; } //IEnumerator接口的特性3 public void Reset() { position = -1; } } //实现IEnumerable接口 public class MyPersons : IEnumerable { string[] strArr = new string[] { "周星驰", "莫言", "贝克汉姆", "林志颖" }; //返回IEnumerator类型的对象 public IEnumerator GetEnumerator() { return new PersonIEnumerator(strArr); } } class Program { static void Main(string[] args) { MyPersons mp = new MyPersons(); foreach (string name in mp) { Console.WriteLine("{0}", name); } Console.ReadKey(); } } /** * -------------执行结果------------- * 周星驰 * 莫言 * 贝克汉姆 * 林志颖 * -------------执行结果------------- */ }
注:C# 语言的 foreach 语句隐藏了枚举数的复杂性。因此,建议使用 foreach,而不直接操作枚举数