• 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 内部实现了一个状态机,具体就不展开了~~
  • 相关阅读:
    题解 P2296 【寻找道路】
    题解 CF534C 【Polycarpus' Dice】
    题解 CF294B 【Shaass and Bookshelf】
    题解 SP4354 【TWINSNOW Snowflakes】
    题解 UVA10294 【Arif in Dhaka (First Love Part 2)】
    FLV文件格式解析部分代码
    关于“无法定位程序输入点getaddrinfo于动态链接库WS32_32.dll上”的问题
    MinGW介绍与使用
    FFMPEG: 0.4.9
    可以处理UTF8编码的md5函数
  • 原文地址:https://www.cnblogs.com/ylws/p/3208062.html
Copyright © 2020-2023  润新知