foreach 迭代器的实现

foreach 迭代器可以遍历所有实现了IEnumerable接口或者提供了 IEnumerable实现的类。

MSDN解释:

在 C# 中,集合类并非必须严格从 IEnumerable 和 IEnumerator 继承才能与 foreach 兼容;只要类有所需的 GetEnumerator、MoveNext、Reset 和 Current 成员,便可以与 foreach 一起使用。省略接口的好处为,使您可以将 Current 的返回类型定义得比 object 更明确,从而提供了类型安全。

查看IEnumerable的实现,只是简单的返回了一个IEnumerator 对象,所有的处理都被委托到了IEnumerator。

    public interface IEnumerable
    {
        IEnumerator GetEnumerator();
    }

    public interface IEnumerator
    {       
        object Current { get; }//获取集合中的当前元素
        bool MoveNext();//将枚举数推进到集合的下一个元素
        void Reset();//将枚举数设置为其初始位置,该位置位于集合中第一个元素之前
    }

  简单示例

    class MyEnumerable:IEnumerable
    {
        int[] values;
        public MyEnumerable(int[] values)
        {
            this.values = values;
        }

        #region IEnumerable 成员

        public IEnumerator GetEnumerator()
        {
            return new MyEnumerator(this);
        }

        #endregion


        class MyEnumerator : IEnumerator
        {
            MyEnumerable parent;
            int position = -1;

            public MyEnumerator(MyEnumerable parent)
            {
                this.parent = parent;
            }

            #region IEnumerator 成员

            public object Current
            {
                get
                {
                    return parent.values[position];
                }
            }

            public bool MoveNext()
            {
                return ++position < parent.values.Length;
            }

            public void Reset()
            {
                position = -1;
            }

            #endregion
        }
    }

由于 IEnumerator接口定义的 Current类型为 Object,所以在使用foreach循环中,获取到的元素类型也是objec。

        static void Main(string[] args)
        {
            int[] values = { 1, 2, 3 };
            MyEnumerable collection = new MyEnumerable(values);
            foreach (var value in collection)
            {
                int temp = value + 1;//编译出错,无法将objec和int类型相加
                Console.WriteLine(temp);
            }
            Console.Read();
        }

可以显示指定foreach中的元素类型 比如  foreach (int value in collection) ,在每次遍历的时候 执行一次强制转换,如果是值类型,还会涉及到装箱和拆箱。
所以我们使用IEnumerable<T>替代IEnumerable

    class MyEnumerable : IEnumerable<int>
    {
        int[] values;
        public MyEnumerable(int[] values)
        {
            this.values = values;
        }

        public IEnumerator<int> GetEnumerator()
        {
            return new MyEnumerator(this);
        }

        class MyEnumerator : IEnumerator<int>
        {           
            public int Current
            {
                get
                {
                    return parent.values[position];
                }
            }
       ………………  } }

最主要的区别就是 Current 的类型为定义的泛型类型,此处为int。

迭代器的实现过于繁琐, 可以使用 yield return 替代繁琐的IEnumerator内嵌类

        public IEnumerator<int> GetEnumerator()
        {
            for (int i = 0; i < values.Length; i++)
                yield return values[i];
        }
yield return 内部实现了一个状态机,具体就不展开了~~
posted @ 2013-07-23 10:20  YLWS  阅读(477)  评论(0编辑  收藏  举报