# 枚举器

如果某个类没有实现接口 IEnumerable,当对这个类的对象使用 foreach 时,我们就会得到一个错误提示:
编译器错误 CS1579
若要使用 foreach 语句循环访问某个集合,该集合必须满足以下要求:

  • 它必须是一个接口、类或结构。
  • 它必须包含一个返回类型的公共 GetEnumerator 方法。
  • 返回类型必须包含一个名为 Current 的公共属性和一个名为 MoveNext 的公共方法。

查找官方文档后发现:

  • GetEnumerator 是在 IEnumerable 中定义的
  • Current 和 MoveNext 是在 IEnumerator 中定义的

# 枚举器接口

  • IEnumerable:可枚举,使类型支持简单迭代(foreach)
  • IEnumerator:枚举器,支持 MoveNext (),可以自己控制迭代的节奏

# 枚举器接口的使用

public class Test : IEnumerable
{
    public int[] TestArray { get; set; }
    public Test(int arrayLength)
    {
        TestArray = new int[arrayLength];
    }
    // 获取枚举器 传统的代码
    //public IEnumerator GetEnumerator()
    //{
    //    return new TestEnumerator() { Target = TestArray };
    //}
    // 获取枚举器 新式的代码
    public IEnumerator GetEnumerator()
    {
        /* yield 的内部
         * 将 yield 之前的所有代码分配到 MoveNext () 中
         * 将 return 后面的数据分配到 Current 中
         */
        /* 代码的执行过程
         * 调用 MoveNext () 时执行
         * 执行到 yield 时(return AllObject [i] 会执行),暂时离开
         * 再次调用 MoveNext () 时继续执行
         */
        for (int i = 0; i < TestArray.Length; i++)
        {
            yield return TestArray[i];
        }
    }
}
/// <summary>
/// 迭代器
/// </summary>
public class TestEnumerator : IEnumerator
{
    public int[] Target;
    private int Index = -1;
    // 获取当前数据
    object IEnumerator.Current
    {
        get
        {
            if (Index >= Target.Length)
            {
                Index = 0;
            }
            return Target[Index];
        }
    }
    public bool MoveNext()
    {
        Index++;
        return Index < Target.Length;
    }
    public void Reset()
    {
        Index = -1;
    }
}

# foreach 的原理

// 以上文中创建的类为基础
private static void Main()
{
    Test test = new Test(5);
    for (int i = 0; i < test.TestArray.Length; i++)
    {
        test.TestArray[i] = i;
    }
    //foreach 的原理
    //1. 获取迭代器:
    IEnumerator temp = test.GetEnumerator();
    //2. 移动到下一个元素
    while (temp.MoveNext())
    {
        //3. 获取元素
        Console.WriteLine(temp.Current);
    }
}