您的位置:首页 > 其它

在自己的对象里实现IEnumerator和IEnumerable

2016-03-17 15:13 507 查看
平时工作中我们经常用foreach来迭代一个集合。比如

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


基本所有的集合都能够foreach,但是必须要实现IEnumerable接口。IEnumerable接口很简单,就只有一个IEnumerator GetEnumerator() 方法。看这个方法的定义就知道,仅仅是公开了另一个接口IEnumerator。而IEnumerator才是真正的支持一个集合的迭代。IEnumerator有1个属性和2个方法。

public object Current;

public void Reset();

public bool MoveNext();

只允许读取集合的数据,而不允许修改。为了详细的讲解,我们来写一个简单的例子,就会一目了然。

首先我们创建一个学生类Student如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IenumerableDemo
{
public class Student
{
#region 私有变量

private readonly string _id;
private string _firstname;
private string _lastname;

#endregion
#region 属性
public string ID { get { return _id; } }

public string FirstName { get { return _firstname; } set { _firstname = value; } }

public string LastName { get { return _lastname; } set { _lastname = value; } }

#endregion

#region 构造函数

public Student(string id, string firstname, string lastname)
{
this._id = id;

this._firstname = firstname;

this._lastname = lastname;
}

#endregion
#region  重写基类object方法

public override string ToString()
{
return string.Format("{0} {1},ID:{2}", _firstname, _lastname, _id);
}

public override bool Equals(object obj)
{
if (obj == null) return false;
if (Object.ReferenceEquals(this, obj)) return true;
if (this.GetType() != obj.GetType()) return false;

Student objstudent = (Student)obj;
if (_id.Equals(objstudent._id)) return true;

return false;
}

public override int GetHashCode()
{
return _id.GetHashCode();
}
#endregion

}
}


接下来我们定义一个ClassList类来承载学生。让我们先忘记Ienmerable。这个类包含一个ArrayList字段_student,在构造函数中模拟3个学生。_student是私有的,不对外公开的。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IenumerableDemo
{
public class ClassList
{

#region private Members

private readonly string _id;

private ArrayList _students;

#endregion

#region Properties
public string ID { get { return _id; } }
#endregion

#region Constructors

public ClassList(string id)
{

this._id = id;
_students = new ArrayList() { new Student("12345", "John", "Smith"), new Student("09876", "Jane", "Doe"), new Student("76403", "Bob", "Johnson") };

}

#endregion

}
}


为了让对象支持foreach 迭代,ClassList类需要实现IEnumerable。因为我们的student是存在ArrayList对象里的,而ArrayList类已经实现了IEnumerable,我们就可以使用ArrayList类的Ienumerable。

public IEnumerator GetEnumerator()
{

return (_students as IEnumerable).GetEnumerator();

}


最终的代码贴一下:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IenumerableDemo
{
public class ClassList:IEnumerable
{

#region private Members

private readonly string _id;

private ArrayList _students;

#endregion

#region Properties
public string ID { get { return _id; } }
#endregion

#region Constructors

public ClassList(string id)
{

this._id = id;
_students = new ArrayList() { new Student("12345", "John", "Smith"), new Student("09876", "Jane", "Doe"), new Student("76403", "Bob", "Johnson") };

}

#endregion

public IEnumerator GetEnumerator()
{

return (_students as IEnumerable).GetEnumerator();

}
}
}


然后我们调用看看使用ArrayList的Ienumerable效果:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IenumerableDemo
{
class Program
{
static void Main(string[] args)
{
ClassList myClass = new ClassList("History 204");

foreach (Student student in myClass)

Console.WriteLine(student);

Console.ReadLine();
}

}

}




看来还是实现了效果。那么接下来我们看看自定义实现IEnumerable。实现IEnumerable其实只要实现IEnumerator接口就可以了。

我们创建我们自己的一个自定义类ClassEnumerator 来实现IEnumerator来完成和上面相同的结果。这个类基本上就只是通过_students的索引来进行迭代,Reset()方法就是把索引设置为-1.Current属性来获取当前的student,MoveNext()来跳到Current的下一个数据,并返回一个boolean来表示是否到了集合最后。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IenumerableDemo
{
public class ClassEnumerator : IEnumerator
{

private ClassList _classList;

private int _index;

public ClassEnumerator(ClassList classList)
{
this._classList = classList;

_index = -1;
}

#region IEnumerator Members

public void Reset()
{
this._index = -1;
}

public object Current
{
get { return _classList.Students[_index]; }
}

public bool MoveNext()
{
_index++;
if (_index >= _classList.Students.Count)
return false;
else
return true;

}
#endregion

}
}


最后修改我们的ClassLst类:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IenumerableDemo
{
public class ClassList : IEnumerable
{

#region private Members

private readonly string _id;

private ArrayList _students;

#endregion

#region Properties
public string ID { get { return _id; } }

public ArrayList Students { get { return _students; } }
#endregion

#region Constructors

public ClassList(string id)
{

this._id = id;
_students = new ArrayList() { new Student("12345", "John", "Smith"), new Student("09876", "Jane", "Doe"), new Student("76403", "Bob", "Johnson") };

}

#endregion

public IEnumerator GetEnumerator()
{

return (IEnumerator)new ClassEnumerator(this);

}
}
}


可已看到还是相当简单的。运行结果和上面是一样的。

下来看看 foreach怎么工作。

其实foreach只是语法糖,最终会被CLR翻译成

IEnumerator enumerator = myClass.GetEnumerator();
while (enumerator.MoveNext())
{
Console.WriteLine((Student)enumerator.Current);

}


我们可以把foreach 换成这样试一下,结果是一样滴。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IenumerableDemo
{
class Program
{
static void Main(string[] args)
{
ClassList myClass = new ClassList("History 204");

//foreach (Student student in myClass)

//    Console.WriteLine(student);

IEnumerator enumerator = myClass.GetEnumerator();
while (enumerator.MoveNext())
{
Console.WriteLine((Student)enumerator.Current);

}

Console.ReadLine();
}

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: