• C# IEnumerable 和 IEnumerator接口浅析


      温故而知新,可以为师矣,有空经常复习一下基础知识是有必要的,并且能加深理解和记忆。

      Foreach常用于循环访问集合,对实现IEnumerable的接口的容器进行遍历,IEnumerable和IEnumerator接口我有时候也有点迷糊,按官方的解释,IEnumerable是枚举器接口,IEnumerator是迭代器接口,从字面意思来看相差不大,逐一分析一下。

    IEnumerable接口

    public interface IEnumerable
    { 
            IEnumerator GetEnumerator();
    }

      继承IEnumerable接口的类需实现暴露出来的GetEnumerator()方法,并返回一个IEnumerator接口对象,看来真正做事的是IEnumerator,F12看一下IEnumerator又有什么鬼东西。

    IEnumerator接口

    public interface IEnumerator
    { 
            object Current { get; }
            bool MoveNext(); 
            void Reset();
    }

      IEnumerator接口有三个东东,一个属性Current,返回当前集合中的元素,方法MoveNext()移动到下一个,遍历不都是向后遍历的嘛,Reset(),字面意思重置,这个容易理解。做个假设:既然IEnumerable接口返回是IEnumerator接口迭代器来实现的,那么仅继承IEnumerator迭代器接口能不能实现一个自定义容器?

    定义一个Phone

    public class Phone 
    {
            public string Name;
            public Phone(string name)
            {
                this.Name = name;
            }
    }

      定义一个名为MyEnumerator迭代器,并现实它接口IEnumerator

    public class MyEnumerator : IEnumerator
    {
            Phone[] p;
            int idx = -1;
            public MyEnumerator(Phone[] t)
            {
                p = t;
            }
            public object Current
            {
                get
                {
                    if (idx == -1)
                        return new IndexOutOfRangeException();
                    return p[idx];
                }
            }
    
            public bool MoveNext()
            {
                idx++;
                return p.Length > idx;
            }
    
            public void Reset()
            {
                idx = -1;
            }
    }
        class Program
        {
            static void Main(string[] args)
            {
           show("-----------IEnumerator------------"); Phone[] phones
    = new Phone[] { new Phone("iPhone 7s"), new Phone("iPhone 6s"), new Phone("iPhone 5s") }; MyEnumerator enumerator = new MyEnumerator(phones); while (enumerator.MoveNext()) { Phone p = enumerator.Current as Phone; show(p.Name); } Console.ReadKey(); } static void show(string i) { Console.WriteLine(i); } }

    结果显示:

      果然不出所料,真正做事情的是IEnumerator接口,即可循环访问自定义的一个容器,不过,初衷是想用Foreach来做循环访问、遍历的。那好,那就只能显示IEnumerable接口来做。稍稍改造一下Phone类:

       public class Phone : IEnumerable
        {
            public string Name ;
            public Phone(string name)
            {
                this.Name = name;
            }
    
            Phone[] p;
            public Phone(Phone[] t)
            {
                p = t;
            }
            public IEnumerator GetEnumerator()
            {
                return new MyEnumerator(p);
            }
        }
    static void Main(string[] args)
            {
                show("-----------IEnumerator------------");
                Phone[] phones = new Phone[] { new Phone("iPhone 7s"), new Phone("iPhone 6s"), new Phone("iPhone 5s") };
                MyEnumerator enumerator = new MyEnumerator(phones);
                while (enumerator.MoveNext())
                {
                    Phone p = enumerator.Current as Phone;
                    show(p.Name);
                }
    
                show("-----------IEnumerable------------");
                Phone phoneList = new Phone(phones);
                foreach (Phone p in phoneList)
                {
                    show(p.Name);
                }
               
                Console.ReadKey();
            }

    结果显示:

      大功告成,再扩展成通用的容器PhonePackage,继承泛型IEnumerable<T>接口即可。

       public class PhonePackage<T> : IEnumerable<T> 
        {
            private List<T> dataList = null;
    
            public void Add(T t)
            {
                if (dataList == null)
                    dataList = new List<T>();
                dataList.Add(t);
            }
    
            public IEnumerator<T> GetEnumerator()
            {
                foreach (T t in dataList)
                {
                    yield return t;
                }
            }
    
            IEnumerator IEnumerable.GetEnumerator()
            {
                foreach (T t in dataList)
                {
                    yield return t;
                }
            }
        }
    static void Main(string[] args)
            {
                show("-----------IEnumerator------------");
                Phone[] phones = new Phone[] { new Phone("iPhone 7s"), new Phone("iPhone 6s"), new Phone("iPhone 5s") };
                MyEnumerator enumerator = new MyEnumerator(phones);
                while (enumerator.MoveNext())
                {
                    Phone p = enumerator.Current as Phone;
                    show(p.Name);
                }
    
                show("-----------IEnumerable------------");
                Phone phoneList = new Phone(phones);
                foreach (Phone p in phoneList)
                {
                    show(p.Name);
                }
                show("-----------IEnumerable<T>------------");
                PhonePackage<Phone> phonePackage = new PhonePackage<Phone>();
                phonePackage.Add(new Phone("iPhone 7s"));
                phonePackage.Add(new Phone("iPhone 6s"));
                phonePackage.Add(new Phone("iPhone 5s"));
                foreach (Phone p in phonePackage)
                {
                    show(p.Name);
                }
                Console.ReadKey();
            }
            static void show(string i)
            {
                Console.WriteLine(i);
            }

    结果显示:

      IEnumerator迭代器接口挺啰嗦的,yield是简化了遍历的语法糖而已。

    参考List<T>源码:http://www.projky.com/dotnet/4.5.1/System/Collections/Generic/List.cs.html

  • 相关阅读:
    Docker,用任何工具链和任何语言来构建任何应用
    从Docker在Linux和Windows下的区别简单理解Docker的层次结构
    Docker在Windows下的安装以及Hello World
    (译)学习如何构建自动化、跨浏览器的JavaScript单元测试
    由Python的super()函数想到的
    PS:蓝天白云的制作
    PS:缝线颜色随着鞋帮颜色的改变发生改变.files
    Windows8 64位运行Silverlight程序不能访问WCF的解决方案
    背景图片之background的用法
    12306订票助手更新
  • 原文地址:https://www.cnblogs.com/EminemJK/p/6428282.html
Copyright © 2020-2023  润新知