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#游戏脚本编程

posted @ 2018-06-10 18:47  SylvanYan  阅读(176)  评论(0编辑  收藏  举报
TOP