c#语言中提供了一种集合的访问方式:foreach。这是一种自动确定边界的单向的访问方式。这次来谈一谈如何实现自定义类中的foreach功能。
比如现在有一个类Forest 的实例MyForest,其中有一个Tree的数组,Tree是我们自己创建的另一个类.。
2 {
3 private Tree[] trees;
4 .
5 .
6 .
7 }
假设有一个类Forest 的实例MyForest, 也许我们希望写这样的代码:
{
DoSomething(tree);
}
而不是:
2 {
3 Tree tree=MyForest.Tree[i];
4 DoSomething(tree);
5 }
显然,使用foreach比用下标来循环更加的直观,对服务类的内部信息的要求也会降低(不要求针对trees的属性),如何在Forest中实现foreach功能呢?
其实,只要是从IEnumerable接口继承下来的类,只要正确实现了接口中的public IEnumerator GetEnumerator()方法,就可以实现foreach,可以看出,这个方法返回的是一个IEnumerator对象,实际上,这个IEnumerator正是实现foreach的核心。先给出代码:
2 {
3 private Tree[] trees;
4 public Forest(Tree[] someTrees)
5 {
6 this.trees=someTrees;
7 }
8
9
10 public IEnumerator GetEnumerator()
11 {
12 return new ForestEnumerator(this);
13 }
14
15 private class ForestEnumerator:IEnumerator
16 {
17 private int position;
18 private Forest forest;
19 public ForestEnumerator(Forest aforest)
20 {
21 this.forest=aforest;
22 this.position=-1;
23 }
24
25 public object Current
26 {
27 get{ return this.forest.trees[this.position];}
28 }
29
30 public bool MoveNext()
31 {
32 if(this.position<this.forest.trees.Length-1)
33 {
34 this.position++;
35 return true;
36 }
37
38 return false;
39 }
40
41 public void Reset()
42 {
43 this.position=-1;
44 }
45 }
46 }
2 {
3 private string name;
4 public Tree(string aname)
5 {
6 this.name = aname;
7 }
8
9 public override string ToString()
10 {
11 return this.name;
12 }
13 }
代码中的10-13行既是GetEnumerator函数的实现,返回一个ForestEnumerator对象,这是一个内部类ForestEnumerator的对象,这个内部类决定了如何执行foreach,可以看见,这个内部类是从IEnumerator继承的,其中有一个属性:Current,两个函数:MoveNext,Reset需要自己实现,这三个函数就是负责foreach执行的,顾名思义Current表示目前对集合的访问进行到何处,MoveNext确定是否还能向下一个元素访问,Reset将访问点移动到集合的首部,准备下一次的访问。至于其中的集合是什么,由你自己决定。其中的变量position是一个游标,指示当前对集合的访问位置。
讲的还算清楚吧,具体的看代码吧。
2 {
3
4 Tree[] trees ={new Tree("apple"),new Tree("pine"),new Tree("no leaves") };
5 Forest forest = new Forest(trees);
6 foreach (Tree tree in forest)
7 Console.WriteLine( tree.ToString());
8 }
我想我是被msdn给骗了,两年以后我才知道。其实根本不用这么麻烦,继承一个IEnumerable接口就行了。