C#学习之自定义类实现foreach

本人初学C#,本文仅供个人整理思路用,那里说得不对,请大家多多指教,万分感激!

本文目的:通过实现 IEnumerable 接口,使得自定义类能使用foreach语句来遍历自身元素

前提知识:数组可以被foreach语句遍历数组中的元素,原因是所有数组的基类都是System.Array ,而System.Array 类实现了IEnumerable接口,可以通过GetEnumerator方法按需提供一个叫做枚举数(enumerator)的对象,枚举数可以依次返回请求的数组的元素。 (注:C#里面的枚举数,也就是枚举器,类似于C++中的迭代器,而C#中的迭代器是另外一个意思。不知我这样理解对否?)

 

第一部分:通过继承IEnumerable接口实现foreach语句

第一步:创建Person类

 

View Code
 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 }


 第二步:创建PeopleEnum类,该类继承IEnumerator接口,实现IEnumerator接口里的MoveNext、Reset方法和Current属性

View Code
 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 }

 

第三步: 创建People类,该类继承IEnumerable接口,实现了GetEnumerator方法,GetEnumerator方法的作用是获取枚举数(返回值是IEnumerator类型的,就是枚举数的类型),在这里是通过返回PeopleEnum类的一个实例来取得枚举数。

View Code
 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 }

 

第四步:People类实现了接口IEnumerable接口,所以People类的实例就能使用foreach来遍历自身元素。主函数测试代码如下:

 

 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 }

 

 

输出如下

 

第二部分:foreach实现的本质

第一部分里的第二步创建PeopleEnum类,并实现里其继承的IEnumerator接口里的MoveNext、Reset方法和Current属性,其实,该类已经具备了遍历自身元素的条件了。

把主函数里的测试的代码改成如下,运行-》输出,结果是一样的

View Code
 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方法的方式,这个留到下一篇文章来说。谢谢!

 

posted @ 2012-02-22 00:43 仙外仙 阅读(...) 评论(...) 编辑 收藏