请直接看以下代码,用foreach来了解Ienumerator和IEnumerable的原理。
class Program
{
static void Main(string[] args)
{
//1.
int[] array_Int;
array_Int = new int[] { 1, 3, 2 };
foreach (int item in array_Int)
{
Console.WriteLine(item);
}
//2.
int[] array_Int2;
array_Int2 = new int[] { 11, 33, 22 };
IEnumerator i = array_Int2.GetEnumerator();
while(i.MoveNext())
{
Console.WriteLine((int)i.Current);
}
Console.ReadLine();
}
}
上述代码的两部分,输出结果是
1
3
2
11
33
22
这是因为ArrayList继承了IEnumerable接口,而IEnumerable内部存在一个方法,其返回值为IEnumerator。
源码如下:
//使用大小会根据需要动态增加的数组来实现 System.Collections.IList 接口。
public class ArrayList : IList, ICollection, IEnumerable, ICloneable
{
}
//公开枚举数,该枚举数支持在非泛型集合上进行简单迭代。
public interface IEnumerable
{
// 摘要:
// 返回一个循环访问集合的枚举数。
//
// 返回结果:
// 一个可用于循环访问集合的 System.Collections.IEnumerator 对象。
IEnumerator GetEnumerator();
}
//支持对非泛型集合的简单迭代。
public interface IEnumerator
{
// 摘要:
// 获取集合中的当前元素。
//
// 返回结果:
// 集合中的当前元素。
object Current { get; }
// 摘要:
// 将枚举数推进到集合的下一个元素。
//
// 返回结果:
// 如果枚举数成功地推进到下一个元素,则为 true;如果枚举数越过集合的结尾,则为 false。
//
// 异常:
// System.InvalidOperationException:
// 在创建了枚举数后集合被修改了。
bool MoveNext();
//
// 摘要:
// 将枚举数设置为其初始位置,该位置位于集合中第一个元素之前。
//
// 异常:
// System.InvalidOperationException:
// 在创建了枚举数后集合被修改了。
void Reset();
}
其中:
1、GetIEnumerator()负责获取枚举器。
2、MoveNext()负责让Current获取下一个值,并判断遍历是否结束。
3、Current负责返回当前指向的值。
4、Rest()负责重置枚举器的状态(在foreach中没有用到)
结论:
1、foreach其实是用来简化对可枚举元素(ArrayList、List等)的遍历代码。
2、亦可创建一个用于被遍历的类,通过实现IEnumerable接口和一个相关的IEnumerator枚举器来实现遍历功能。