• C#笔记——5.迭代器


    迭代器(Iterator)简介:
    设计模式中的迭代器模式,分离集合对象的遍历行为,抽象出迭代器负责,来做到既不暴露集合的内部结构,又可以让外部代码透明的访问集合内部的数据。
    因为迭代器模式应用非常普遍,所以各种编程语言都对迭代器模式进行了封装。

    .Net的迭代器模式

    IEnumerable接口:

        public interface IEnumerable{
            IEnumerator GetEnumerator();
        }
    

    实现了IEnumerable接口的集合表明该集合能够提供一个Enumerator(枚举器)对象,支持当前的遍历集合。该接口只有一个GetEnumerator()成员方法。

    IEnumerator接口:

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

    MoveNext()方法调整遍历指针移向集合的下一个元素。注意,遍历指针的初始位置是集合中第一个元素的前面。要指向第一个元素,必须先调用一次
    MoveNext()方法。该方法返回一个布尔值,如果成功遍历到下一个元素,则返回true;如果指针移出末尾,则返回false。
    Reset()方法用于设置遍历指针指向初始位置,即集合中第一个元素的前面。
    Current属性返回集合中当前对象的引用。

    IEnumerable和IEnumerator的区别:

    1、一个Collection要支持foreach方式的遍历,必须实现IEnumerable接口(亦即,必须以某种方式返回IEnumerator object)。

    2、IEnumerator object具体实现了迭代器(通过MoveNext(),Reset(),Current)。

    3、从这两个接口的用词选择上,也可以看出其不同:IEnumerable是一个声明式的接口,声明实现该接口的class是“可枚举(enumerable)”的,但并没有说明如何实现枚举器(iterator);IEnumerator是一个实现式的接口,IEnumerator object就是一个iterator。

    4、IEnumerable和IEnumerator通过IEnumerable的GetEnumerator()方法建立了连接,client可以通过IEnumerable的GetEnumerator()得到IEnumerator object,在这个意义上,将GetEnumerator()看作IEnumerator object的factory method也未尝不可。

    .Net的迭代器实现

    对一个自定义的类实现IEnumerable接口示例代码:

    /// <summary>
    /// The Class Which We Want To Implement the IEnumerable interface.
    /// </summary>
    public class UserData : IEnumerable
    {
        public List<Person> UsersList { get; set; }
    
        public UserData() { }
    
        public UserData(List<Person> list) => UsersList = list;
    
        //Implementation The Interface`s GetEnumerable method
        IEnumerator IEnumerable.GetEnumerator()
        {
            return (IEnumerator)GetEnumerator();
        }
    
        //Class method
        public PersonEnum GetEnumerator()
        {
            return new PersonEnum(UsersList);
        }
    }
    
    /// <summary>
    /// The Class We Should Also Implement The IEnumerator Interface ,When We Want To Implement The IEnumerable Interface.
    /// </summary>
    public class PersonEnum : IEnumerator
    {
        public List<Person> _pList;
        //Mark The Position Of The Current Element.
        int pos = -1;
    
        public PersonEnum(List<Person> list)
        {
            _pList = list;
        }
    
        //The Core Of The IEnumerator
        object IEnumerator.Current
        {
            get
            {
                return Current;
            }
        }
    
        //The Class Mathod
        public Person Current
        {
            get
            {
                try
                {
                    return _pList[pos];
                }
                catch(IndexOutOfRangeException)
                {
                    throw new IndexOutOfRangeException();
                }
            }
        }
    
        public bool MoveNext()
        {
            pos++;
            return (pos < _pList.Count);
        }
    
        public void Reset()
        {
            pos = -1;
        }
    }
    

    在UserData类实现了IEnumerable接口之后,我们便可以使用foreach来进行迭代访问了

    class Program
    {
        private const string filePath = "UserList.json";
    
        static void Main(string[] args)
        {
            using (StreamReader streamReader = File.OpenText(filePath))
            {
                string str = streamReader.ReadToEnd();
                UserData u = JsonMapper.ToObject<UserData>(str);
    
                //Implement the IEnumerable in the Class UserData To Support the use of foreach.
                foreach (Person p in u)
                {
                    Console.WriteLine(p.ToString());
                }
            }
    
            Console.ReadKey();
        }
    }
    

    使用的简单类代码(可忽略,重点是上方IEnumerable接口的实现代码):

    [ProtoContract]
    [ProtoInclude(5, typeof(Developer))]
    [ProtoInclude(6, typeof(Designer))]
    public class Person
    {
        [ProtoMember(1)]
        public String Name { get; set; }
        [ProtoMember(2)]
        public String ID { get; set; }
        [ProtoMember(3)]
        public bool Gender { get; set; }
        [ProtoMember(4)]
        public int Age { get; set; }
    
        public Person(string name, string id, bool gender, int age)
        {
            Name = name;
            ID = id;
            Gender = gender;
            Age = age;
        }
        public Person() { }
    
        public override string ToString()
        {
            return "Name : " + Name + ", ID : " + ID + " , Gender :" + Gender + " , Age :  " + Age;
        }
    }
    
    [ProtoContract]
    public class Developer : Person
    {
        [ProtoMember(1)]
        public String Languages { get; set; }
        public Developer(string name, string id, bool gender, int age, string language) : base(name, id, gender, age)
        {
            Languages = language;
        }
        public Developer() : base() { }
        public override string ToString()
        {
            return base.ToString() + " , Work with the languages : " + Languages + " .";
        }
    }
    
    [ProtoContract]
    public class Designer : Person
    {
        [ProtoMember(1)]
        public string Software { get; set; }
    
        public Designer(string name, string id, bool gender, int age, string software) : base(name, id, gender, age)
        {
            Software = software;
        }
    
        public Designer() : base() { }
    
        public override string ToString()
        {
            return base.ToString() + ", Work with software : " + Software + " .";
        }
    }
    

    REF
    深入理解C#、C#高级编程、C#游戏脚本编程

  • 相关阅读:
    datagridview中读取数据判断+考勤每月上班天数判断
    dateTimePicker日期比较+时间段内查询+员工查询薪资步骤+datagridview
    c#word 存取
    位图去空白
    过桥问题
    Dominos 2(DFS)(容器)
    poj 3421(三分)
    poj 3186(DP)
    安装Ubuntu
    poj 3273(二分)
  • 原文地址:https://www.cnblogs.com/sylvan/p/9163993.html
Copyright © 2020-2023  润新知