• IEnumerable 和 IEnumerator


    Original Article

    程序下载

    Often you want to be able to enumerate through a collection of objects using the foreach statement in C#:

    Using foreach in C#

    foreach (Student student in myClass)
         Console.WriteLine(student);

    To be able to pull that off, myClass must implement IEnumerable:

    IEnumerable Defined

    Exposes the enumerator, which supports a simple iteration over a collection.

    public IEnumerator GetEnumerator();

    As is says above, IEnumerable just exposes another interface, called IEnumerator:

    IEnumerator Defined

    Supports a simple iteration over a collection.  Enumerators only allow reading the data in the collection. Enumerators cannot be used to modify the underlying collection.

    publicobject Current;
    publicvoid Reset();
    publicbool MoveNext();

    To see this in action, let’s create an example by which we can iterate through a list of students in a class using theforeach statement in C#.

    First, we need to create a Student Class as shown below.  At the minimum we want to override ToString()(Overriding System.Object.ToString() and IFormattable) so it says something meaningful and for kicks I decided to override Equals() and GetHashCode() (Object Identity vs. Object Equality – Overriding System.Object.Equals(Object obj)) only as an example.

    Student Class
    publicclass Student
    {
    #region Private Members

    privatereadonlystring _id;
    privatestring _firstname;
    privatestring _lastname;

    #endregion

    #region Properties

    publicstring ID { get { return _id; } }

    publicstring Firstname
    {
    get { return _firstname; }
    set { _firstname = value; }
    }

    publicstring Lastname
    {
    get { return _lastname; }
    set { _lastname = value; }
    }

    #endregion

    #region Constructors

    public Student(string id, string firstname, string lastname)
    {
    _id
    = id;
    _firstname
    = firstname;
    _lastname
    = lastname;
    }

    #endregion

    #region Overriding System.Object

    publicoverridestring ToString()
    {
    return String.Format({0} {1}, ID: {2}, _firstname, _lastname, _id);
    }

    publicoverridebool Equals(object obj)
    {
    if (obj ==null) returnfalse;
    if (Object.ReferenceEquals(this,obj)) returntrue;
    if (this.GetType() != obj.GetType()) returnfalse;

    Student objStudent = (Student)obj;
    if (_id.Equals(objStudent._id)) returntrue;

    returnfalse;
    }

    publicoverrideint GetHashCode()
    {
    return _id.GetHashCode();
    }

    #endregion
    }

    We now need a custom class, called ClassList, that essentially holds the students.  Forgetting IEnumerable for a moment, here is my barebones class.  The class contains an ArrayList, called _students, which is populated with 3 students in its constructor.  The list of students is private to ClassList and is currently not exposed outside of the class.

    ClassList Class with no IEnumerable
    publicclass ClassList
    {
    #region Private Members

    privatereadonlystring _id;

    private ArrayList _students;

    #endregion

    #region Properties

    publicstring ID { get { return _id; } }

    #endregion

    #region Constructors

    public ClassList(string id)
    {
    _id
    = id;

    _students =new ArrayList();

    _students.Add(new Student(12345, John, Smith));
    _students.Add(
    new Student(09876, Jane, Doe));
    _students.Add(
    new Student(76403, Bob, Johnson));
    }

    #endregion

    }

    To support iteration using foreach on the class, I need to implement IEnumerable on ClassList.  Since my students are in an ArrayList, and I know ArrayList implements IEnumerable, I am going to “cheat” and pass back theIEnumerator for _students:

    Using The ArrayList’s IEnumerator
    public IEnumerator GetEnumerator()
    {
    return (_students as IEnumerable).GetEnumerator();
    }

    This will allow me to use foreach on ClassList and here is sample code you can run to see how it works:

    Example 1: Testing The ArrayList’s IEnumerator
    using System;
    using System.Collections;

    publicclass Student
    {
    #region Private Members

    privatereadonlystring _id;
    privatestring _firstname;
    privatestring _lastname;

    #endregion

    #region Properties

    publicstring ID { get { return _id; } }

    publicstring Firstname
    {
    get { return _firstname; }
    set { _firstname = value; }
    }

    publicstring Lastname
    {
    get { return _lastname; }
    set { _lastname = value; }
    }

    #endregion

    #region Constructors

    public Student(string id, string firstname, string lastname)
    {
    _id
    = id;
    _firstname
    = firstname;
    _lastname
    = lastname;
    }

    #endregion

    #region Overriding System.Object

    publicoverridestring ToString()
    {
    return String.Format({0} {1}, ID: {2}, _firstname, _lastname, _id);
    }

    publicoverridebool Equals(object obj)
    {
    if (obj ==null) returnfalse;
    if (Object.ReferenceEquals(this,obj)) returntrue;
    if (this.GetType() != obj.GetType()) returnfalse;

    Student objStudent = (Student)obj;
    if (_id.Equals(objStudent._id)) returntrue;

    returnfalse;
    }

    publicoverrideint GetHashCode()
    {
    return _id.GetHashCode();
    }

    #endregion
    }

    publicclass ClassList : IEnumerable
    {
    #region Private Members

    privatereadonlystring _id;

    private ArrayList _students;

    #endregion

    #region Properties

    publicstring ID { get { return _id; } }

    #endregion

    #region Constructors

    public ClassList(string id)
    {
    _id
    = id;

    _students =new ArrayList();

    _students.Add(new Student(12345, John, Smith));
    _students.Add(
    new Student(09876, Jane, Doe));
    _students.Add(
    new Student(76403, Bob, Johnson));
    }

    #endregion

    #region IEnumerable Members

    public IEnumerator GetEnumerator()
    {
    return (_students as IEnumerable).GetEnumerator();
    }

    #endregion

    }

    publicclass MyClass
    {
    publicstaticvoid Main()
    {
    ClassList myClass
    =new ClassList(History 204);

    foreach (Student student in myClass)
    Console.WriteLine(student);

    Console.ReadLine();
    }
    }

    If that is all the functionality you need, then passing the ArrayList’s IEnumerator is the ticket.  No sense creating your own IEnumerator if you don’t have to.

    However, we can create our own class, called ClassEnumerator, that implements IEnumerator and accomplishes the same thing as above.  The class essentially just iterates through the _students arraylist using an index.  Reset() sets the index back to -1. MoveNext() jumps ahead and returns a boolean as to whether we have hit the end.  And, theCurrent property gets the current student.

    ClassEnumerator
    privateclass ClassEnumerator : IEnumerator
    {
    private ClassList _classList;
    privateint _index;

    public ClassEnumerator(ClassList classList)
    {
    _classList
    = classList;
    _index
    =-1;
    }

    #region IEnumerator Members

    publicvoid Reset()
    {
    _index
    =-1;
    }

    publicobject Current
    {
    get
    {
    return _classList._students[_index];
    }
    }

    publicbool MoveNext()
    {
    _index
    ++;
    if (_index >= _classList._students.Count)
    returnfalse;
    else
    returntrue;
    }

    #endregion
    }

    We will stick ClassEnumerator within ClassList and pass it back via the IEnumerable interface. Here is the entire code listing using our custom IEnumerator:

    Testing ClassEnumerator
    using System;
    using System.Collections;

    publicclass Student
    {
    #region Private Members

    privatereadonlystring _id;
    privatestring _firstname;
    privatestring _lastname;

    #endregion

    #region Properties

    publicstring ID { get { return _id; } }

    publicstring Firstname
    {
    get { return _firstname; }
    set { _firstname = value; }
    }

    publicstring Lastname
    {
    get { return _lastname; }
    set { _lastname = value; }
    }

    #endregion

    #region Constructors

    public Student(string id, string firstname, string lastname)
    {
    _id
    = id;
    _firstname
    = firstname;
    _lastname
    = lastname;
    }

    #endregion

    #region Overriding System.Object

    publicoverridestring ToString()
    {
    return String.Format({0} {1}, ID: {2}, _firstname, _lastname, _id);
    }

    publicoverridebool Equals(object obj)
    {
    if (obj ==null) returnfalse;
    if (Object.ReferenceEquals(this,obj)) returntrue;
    if (this.GetType() != obj.GetType()) returnfalse;

    Student objStudent = (Student)obj;
    if (_id.Equals(objStudent._id)) returntrue;

    returnfalse;
    }

    publicoverrideint GetHashCode()
    {
    return _id.GetHashCode();
    }

    #endregion
    }

    publicclass ClassList : IEnumerable
    {
    #region Private Members

    privatereadonlystring _id;

    private ArrayList _students;

    #endregion

    #region Properties

    publicstring ID { get { return _id; } }

    publicint TotalStudents { get { return _students.Count; } }

    #endregion

    #region Constructors

    public ClassList(string id)
    {
    _id
    = id;

    _students =new ArrayList();

    _students.Add(new Student(12345, John, Smith));
    _students.Add(
    new Student(09876, Jane, Doe));
    _students.Add(
    new Student(76403, Bob, Johnson));
    }

    #endregion

    #region IEnumerable Members

    public IEnumerator GetEnumerator()
    {
    return (IEnumerator)new ClassEnumerator(this);
    }

    #endregion

    #region ClassEnumerator

    privateclass ClassEnumerator : IEnumerator
    {
    private ClassList _classList;
    privateint _index;

    public ClassEnumerator(ClassList classList)
    {
    _classList
    = classList;
    _index
    =-1;
    }

    #region IEnumerator Members

    publicvoid Reset()
    {
    _index
    =-1;
    }

    publicobject Current
    {
    get
    {
    return _classList._students[_index];
    }
    }

    publicbool MoveNext()
    {
    _index
    ++;
    if (_index >= _classList._students.Count)
    returnfalse;
    else
    returntrue;
    }

    #endregion
    }

    #endregion
    }

    publicclass MyClass
    {
    publicstaticvoid Main()
    {
    ClassList myClass
    =new ClassList(History 204);

    Console.WriteLine(Class: {0}, Total Students: {1} ,
    myClass.ID, myClass.TotalStudents.ToString());

    foreach (Student student in myClass)
    Console.WriteLine(student);

    Console.ReadLine();
    }
    }

  • 相关阅读:
    递归分治策略
    矩阵连乘问题
    棋盘覆盖问题
    选择排序
    Dijkstra的双栈算术表达式求值算法
    斐波那契数列
    二分算法
    Linux服务器上tengine的安装配置
    Excel Sheet Column Number
    Excel Sheet Column Title
  • 原文地址:https://www.cnblogs.com/shawnzxx/p/3518040.html
Copyright © 2020-2023  润新知