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;
            }
  • 相关阅读:
    理解C#中的 async await
    kube-proxy IPVS 模式的工作原理
    Kilo 使用教程
    Wireguard 全互联模式(full mesh)配置指南
    我为什么不鼓吹 WireGuard
    iTerm2 实现 ssh 自动登录,并使用 Zmodem 实现快速传输文件
    在 Docker Desktop 中启用 K8s 服务
    ABP 适用性改造
    ABP 适用性改造
    在 ASP.NET Core 应用中使用 Cookie 进行身份认证
  • 原文地址:https://www.cnblogs.com/lzzhang/p/5067408.html
Copyright © 2011-2022 走看看