本人初学C#,本文仅供个人整理思路用,那里说得不对,请大家多多指教,万分感激!
本文目的:通过实现 IEnumerable 接口,使得自定义类能使用foreach语句来遍历自身元素
前提知识:数组可以被foreach语句遍历数组中的元素,原因是所有数组的基类都是System.Array ,而System.Array 类实现了IEnumerable接口,可以通过GetEnumerator方法按需提供一个叫做枚举数(enumerator)的对象,枚举数可以依次返回请求的数组的元素。 (注:C#里面的枚举数,也就是枚举器,类似于C++中的迭代器,而C#中的迭代器是另外一个意思。不知我这样理解对否?)
1 public class Person
2 {
3 string Name;
4 int Age;
5
6 public Person(string name, int age)
7 {
8 Name = name;
9 Age = age;
10 }
11
12 public override string ToString()
13 {
14 return "Name: " + Name + "\tAge: " + Age;
15 }
16 }
1 public class PeopleEnum : IEnumerator
2 {
3 private Person[] _people;
4 int position = -1;
5
6 public PeopleEnum(Person[] list)
7 {
8 _people = list;
9 }
10
11 public bool MoveNext()
12 {
13 position++;
14 return (position < _people.Length);
15 }
16
17 public void Reset()
18 {
19 position = -1;
20 }
21
22 public object Current
23 {
24 get
25 {
26 return _people[position];
27 }
28 }
29
30 }
1 public class People : IEnumerable
2 {
3 private Person[] _people;
4 public People(Person[] pArray)
5 {
6 _people = new Person[pArray.Length];
7 for (int i = 0; i < pArray.Length; i++)
8 {
9 _people[i] = pArray[i];
10
11 }
12 }
13
14 public IEnumerator GetEnumerator()
15 {
16 return new PeopleEnum(_people);
17 }
18 }
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 Person[] persons = new Person[]
6 {
7 new Person("aaa", 20),
8 new Person("bbb", 21),
9 new Person("ccc", 22)
10 };
11
12 People peopleList = new People(persons);
13
14 foreach (var item in peopleList)
15 {
16 System.Console.WriteLine(item);
17 }
18
19 System.Console.ReadKey();
20 }
21 }
输出如下
第一部分里的第二步创建PeopleEnum类,并实现里其继承的IEnumerator接口里的MoveNext、Reset方法和Current属性,其实,该类已经具备了遍历自身元素的条件了。
把主函数里的测试的代码改成如下,运行-》输出,结果是一样的
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 Person[] persons = new Person[]
6 {
7 new Person("aaa", 20),
8 new Person("bbb", 21),
9 new Person("ccc", 22)
10 };
11
12 while (peopleEnum.MoveNext())
13 {
14 System.Console.WriteLine(peopleEnum.Current);
15 }
16
17 System.Console.ReadKey();
18 }
19 }
但是不能使用foreach语句,为什么呢?因为使用foreach语句类必须提供GetEnumerator方法获取该类的枚举数,然后编译器通过这个枚举数来调用IEnumerator接口里的 MoveNext、Reset方法和Current属性实现对类元素的遍历。
给PeopleEnum类添加一个GetEnumerator方法
1 public IEnumerator GetEnumerator()
2 {
3 return this;
4 }
主函数测试代码改成如下:
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 Person[] persons = new Person[]
6 {
7 new Person("aaa", 20),
8 new Person("bbb", 21),
9 new Person("ccc", 22)
10 };
11
12
13 PeopleEnum peopleEnum = new PeopleEnum(persons);
14
15 foreach (var item in peopleEnum)
16 {
17 System.Console.WriteLine(item);
18
19 }
20
21 System.Console.ReadKey();
22 }
23 }
运行,成功!
结论:一个类想要实现foreach,就得提供GetEnumerator方法获取该类的枚举数(就是返回一个IEnumerator接口类型的变量)。实现GetEnumerator方法(或者称为获取枚举数)的方式有很多种,本文采用了实现IEnumerable接口的方式(本质上也就是实现IEnumerator接口,只不过把GetEnumerator方法挪出去了而已)。其他还有例如通过迭代器来实现GetEnumerator方法的方式,这个留到下一篇文章来说。谢谢!