数组可以被foreach语句遍历数组中的元素,原因是数组可以按需提供一个叫做枚举数(enumerator)的对象.枚举数可以依次返回请求的数组的元素.
对于有枚举数的类型而言,必须有一个方法来获取它们.在.NET中获取一个对象枚举数的标准用法是调用对象的GetEnumerator方法.实现GetEnumerator方法的类型叫做可枚举类型(enumerable),数组就是可枚举类型. 要注意枚举数(enumerator)和可枚举类型(enumerable)的区别和联系. 枚举数是可以依次返回集合项的类对象,可枚举类型是带有GetEnumerator方法的类型,它返回枚举数. 当foreach被用来遍历可枚举类型时,它就会执行如下的行为: 1,通过调用GetEnumerator方法获取对象的枚举数. 2,从枚举数中请求每一项并且把它作为迭代变量,代码可以读但不可以改变. 枚举数共有3种,可以用以下方式来实现枚举数: 1 IEnumerator/IEnumerable接口 ,叫做非泛型接口形式. 2 IEnumerator<T>/IEnumerable<T>接口, 叫做泛型接口形式. 3 不使用接口形式. IEnumerator接口 IEnumerator接口包含3个函数成员:Current,MoveNext,Reset Current返回序列中当前项的属性,它是一个只读属性.返回object类型的引用,所以可以返回任何类型. MoveNext是把枚举数位置前进到集合的下一项的方法,它返回布尔值,指示新位置是有效位置还是已经超过了序列的尾部.如果是已经到达了尾部,则返回false. Reset方法把位置重置为原始状态. 查看下面的代码:int[] MyArray = { 10, 11, 12, 13 }; //创建数组 IEnumerator ie = MyArray.GetEnumerator(); //获取枚举数 while (ie.MoveNext()) //移到下一项 Console.WriteLine((int)ie.Current); //获取当前项并输入 枚举数的初始位置是-1,所以要想获取第一个元素就必须执行MoveNext()方法. 上面的代码就是调用枚举数的Current和MoveNext成员函数手工地遍历数组中的元素. 或者可以直接使用foreach直接获取: foreach(int i in MyArray) Console.WriteLine(i); 下面列出一个颜色名数组的枚举数类: using System.Collections; class ColorEnumerator : IEnumerator { private string[] Colors; private int Position = -1; public object Current { get { if (Position == -1) throw new InvalidOperationException(); if (Position == Colors.Length) throw new InvalidOperationException(); ; return Colors[Position]; } } public bool MoveNext() { if (Position < Colors.Length - 1) { Position ++; return true; } else return false; } public void Reset() { Position = -1; } public ColorEnumerator(string[] theColors) //构造函数 { Colors = new string[theColors.Length]; for (int i = 0; i < theColors.Length - 1; i++) Colors[i] = theColors[i]; } } 以上代码就构造了一个完整的枚举数类型.下面生成对象返回枚举数. class Program { static void Main() { ColorEnumerator ce = new ColorEnumerator(new string[]{"yellow","red","white","black"}); while (ce.MoveNext()) Console.WriteLine((string)(ce.Current)); Console.ReadKey(); } } 如果要用foreach来遍历枚举数,需要再定义一个可枚举类型的类,这个类要实现IEnumerable接口的功能. public interface IEnumerable { IEnumerator GetEnumerator(); } class MyEnumerable : IEnumerable //定义一个可枚举类型的类 { string[] MyColor = new string[] { "yellow", "red", "black", "white" }; public IEnumerator GetEnumerator() //实现接口 { return new ColorEnumerator(MyColor); //返回一个枚举数的对象 } } 现在就可以使用foreach来遍历可枚举类型对象的所有元素了. class Program { static void Main() { MyEnumerable me = new MyEnumerable(); foreach (string i in me) Console.WriteLine(i); Console.ReadKey(); } }
总结一下,如果想遍历一个对象中的所有元素,可以把对象设为枚举数类型(实现IEnumerator接口)和可枚举的类类型(实现IEnumerable接口),前者需要实现IEnumerator接口的Current,MoveNext和Rest成员函数,后者需要实现IEnumerable接口的GetEnumerator成员函数,由于GetEnumerator返回的是IEnumerator对象,所以还要建立一个派生于IEnumerator的枚举数类,在这个类中实现Current,MoveNext和Reset成员函数.派生于IEnumerable的类可以使用foreach代码来遍历对象中的全部元素.
原文链接:http://sywxy.iteye.com/blog/1317750