IEnumerable、IEnumerator接口(迭代器)
介绍
IEnumerable 提供了可以迭代的能力,而这种能力是通过内部的可迭代对象来实现了,这个对象就是IEnumerator
有了它们,我们不需要将内部集合暴露出去,外界只需要访问我的迭代器接口方法即可遍历数据。
foreach
在C#中,使用foreach语句来遍历集合。foreach语句是微软提供的语法糖,使用它可以简化C#内置迭代器的使用复杂性。编译foreach语句,会生成调用GetEnumerator和MoveNext方法以及Current属性的代码。
反编译foreach,生成类似下面这段代码:
IEnumerator<Student> studentEnumerator = studentList.GetEnumerator();
while (studentEnumerator.MoveNext())
{
var currentStudent = studentEnumerator.Current as Student;
Console.WriteLine("Id = {0}, Name = {1}, Age = {2}", currentStudent.Id, currentStudent.Name, currentStudent.Age);
}
案例
案例1:给类增加迭代器功能
public class StudentSet : IEnumerable
{
private Student[] students;
public StudentSet(Student[] inputStudents)
{
students = new Student[inputStudents.Length];
for (int i = 0; i < inputStudents.Length; i++)
{
students[i] = inputStudents[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)GetEnumerator();
}
public StudentEnumerator GetEnumerator()
{
return new StudentEnumerator(students);
}
}
public class StudentEnumerator : IEnumerator
{
public Student[] students;
int position = -1;
public StudentEnumerator(Student[] students)
{
this.students = students;
}
public bool MoveNext()
{
position++;
return (position < students.Length);
}
public void Reset()
{
position = -1;
}
object IEnumerator.Current
{
get
{
return Current;
}
}
public Student Current
{
get
{
try
{
return students[position];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
}
案例2:使用yield实现迭代器功能
有两种实现迭代器的方式,一是自己继承IEnumerable接口,比较复杂;二是使用yield,简化操作。
public class MyCollection
{
private int[] list = new int[] { 1, 2, 3, 4 };
public IEnumerator<int> GetEnumerator()
{
for (int i = 0; i < list.Length; i++)
{
yield return list[i];
}
}
}
MyCollection col = new MyCollection();
foreach (var item in col)
{
Console.WriteLine(item);
}