zoukankan      html  css  js  c++  java
  • IEnumerable实践应用

    1.集合想要支持foreach方式遍历,需要返回一个迭代器(IEnumerator),foreach会自动调用迭代器的状态迁移(MoveNext()、Curent、Reset())

    #region Assembly mscorlib.dll, v4.0.0.0
    // C:Program Files (x86)Reference AssembliesMicrosoftFramework.NETFrameworkv4.5mscorlib.dll
    #endregion
    
    using System;
    using System.Runtime.InteropServices;
    
    namespace System.Collections
    {
        // Summary:
        //     Supports a simple iteration over a nongeneric collection.
        [ComVisible(true)]
        [Guid("496B0ABF-CDEE-11d3-88E8-00902754C43A")]
        public interface IEnumerator
        {
            object Current { get; }
    
            bool MoveNext();
          
            void Reset();
        }
    }

    2.IEnumerable接口定制了foreach的需求

    #region Assembly mscorlib.dll, v4.0.0.0
    // C:Program Files (x86)Reference AssembliesMicrosoftFramework.NETFrameworkv4.5mscorlib.dll
    #endregion
    
    using System.Runtime.InteropServices;
    
    namespace System.Collections
    {
        // Summary:
        //     Exposes the enumerator, which supports a simple iteration over a non-generic
        //     collection.
        [ComVisible(true)]
        [Guid("496B0ABE-CDEE-11d3-88E8-00902754C43A")]
        public interface IEnumerable
        {
            [DispId(-4)]
            IEnumerator GetEnumerator();
        }
    }

    3.类似于List的列表定义如下:

        /// <summary>
        /// 列表
        /// </summary>
        class MyList : ArrayList, IEnumerable<object>
        {
    
            // 迭代器返回  
            public IEnumerator<object> GetEnumerator()
            {
                return new MyListEnumerator(this);
            }
    
            /// <summary>
            /// 1.由于IEnumerable<T>继承自IEnumerable,因此必须实现其方法
            /// 2.由于已经存在同名方法,因此需要显示实现
            /// </summary>
            /// <returns></returns>
            IEnumerator IEnumerable.GetEnumerator()
            {
                //return GetEnumerator(); // IEnumerator是IEnumerator<T>的基类  
                return null;
            }
        }
    
        /// <summary>
        /// 为列表定制的迭代器
        /// </summary>
        class MyListEnumerator : IEnumerator<object>
        {
            private int current = -1;
            private MyList _mylist;
    
            public MyListEnumerator(MyList mylist)
            {
                _mylist = mylist;
                current = _mylist == null || _mylist.Count == 0 ? -1 : 0;
            }
    
            public bool MoveNext()
            {
                current++;
                return _mylist != null && _mylist.Count > current;
            }
    
            object IEnumerator<object>.Current
            {
                get
                {
                    if (_mylist != null && _mylist.Count > current) return _mylist[current];
                    return null;
                }
            }
            // 1.由于IEnumerable<out T>继承自IEnumerable,因此必须实现其方法
            // 2.由于已经存在同名方法,因此需要显示实现
            object IEnumerator.Current 
            { 
                get 
                {
                    //if (_mylist != null && _mylist.Count > current)return _mylist[current]; 
                    return null; 
                } 
            }
    
            public void Reset()
            {
                current = _mylist == null || _mylist.Count == 0 ? -1 : 0;
            }
    
            // IEnumerator<T>继承了IDisposable,为了遍历完后清理状态,所以需要实现该方法  
            // 该方法在foreach循环完毕后自动调用  
            public void Dispose() { }
        }

    4.IEnumerator作为迭代器,源于底层编程语言指针的启发;

       引用类型不同于值类型的一个重要特点就是用到的时候才会进行真正的处理

       .Net中yield关键字对此有很好的支持,以下举例说明:

           static void Main(string[] args)
            {
                var list = GetStrings(5);
                foreach (var item in list)
                {
                    Console.WriteLine(item);
                }
    
                list = GetStrings(10);
                foreach (var item in list)
                {
                    Console.WriteLine(item);
                }
    
                Console.ReadLine();
            }
    运行结果:
    /// <summary> /// 1.yield return将单次运算结果放入IEnumerable集合中 /// 2.yield break中断当前迭代器的作用域 /// </summary> /// <param name="length"></param> /// <returns></returns> public static IEnumerable<string> GetStrings(int length = 0) { for (int i = 0; i < length; i++) { if (i < 5) { yield return string.Format("第{0}次调用", i); } else { yield break; } } Console.WriteLine("yield break之后在迭代作用域内的代码不会再被执行"); }

    补充:上面GetStrings传统上很多人习惯如下写法,但是这样做的时间开销是n*m,其中n为待运算列表长度,m为第一次遍历长度,这就是为什么上面强调用到的时候才会进行真正的处理

     public static List<string> GetStrings(int length = 0)
            {
                var result = new List<string>();
                for (int i = 0; i < length; i++)
                {
                    if (i < 5)
                    {
                        result.Add(string.Format("第{0}次调用", i));
                    }
                }
                return result;
            }
  • 相关阅读:
    白盒测试相关内容总结
    黑盒测试相关内容总结
    int.parse的出错异常处理
    逃的过初一逃不过十五之三个输入框文本内容检测的实现及测试
    EditBox问题等价类划分
    关于课堂上Exercise#1的讨论
    js中关于事件处理函数名后面是否带括号的问题
    关于提升和作用域的一道有趣的题目
    绝对定位对元素宽度的影响
    js异步函数队列
  • 原文地址:https://www.cnblogs.com/lzzhang/p/5067408.html
Copyright © 2011-2022 走看看