foreach是C#和Visual Basic.NET编程语言中的一种强有力的构造机制,采用foreach可以声明多个对象。可是受管C++的语言规范中则没有这一很有用的构造方法,因此我写了这篇文章教你如何在编程实践中采用它。
受管C++ 为数据类型的存储和检索提供了许多功能强大的集合类。这些类都提供了一个IEnumerable 接口。该接口的唯一应用目的就是暴露GetEnumerator () 方法,由该方法返回一个实现IEnumerator 接口的对象指针。IEnumerator 接口暴露的方法允许所有的集合按照同样的方式被声明。正是由于这个 IEnumerator 接口的存在我们才能实现 foreach的循环构造。
IEnumerator 接口相当简单。你可以用 MoveNext () 方法把枚举器(enumerator)应用到下一个对象,然后用Current(当前)属性从集合中获得对象。当 MoveNext () 方法返回false时表示枚举过程已经达到集合的末尾。如果你要把枚举器移回到集合的开头则可以调用Reset () 方法实现这一目的。
我们希望foreach循环构造过程隐藏IEnumerable 的全部细节乃至IEnumerator 接口自身,所以我们如清单A所示在Foreach类中封装了所有的细节。
我们需要用到两个私有的成员变量。第一个变量是collection,我们存储当前的集合类,这样我们就知道它是一个新的循环还是现有循环的延续。第二变量是
enumerator。我们保存当前的枚举器以便重复声明的时候能从集合停止循环的地方继续操作。
foreach () 方法用一个指向指针对象的指针和任意集合类作为其参数。更准确地说,第二个参数就是实现 IEnumerable 接口的任意类,原因在于,Array(数组)类并不属于System::Collections名称空间的成员。不过我还是认为数组也是一种集合。
foreach () 方法首先检查是否正在枚举同一集合。集合类被初次枚举的时候会获取enumerator并同collection集合一道保存。之后就是标准的枚举代码了。接着调用MoveNext () 方法对象即通过current属性被从集合中提取出来。我们保存 MoveNext () 方法的返回值以便它能被 foreach()方法返回。Current属性则保存在取出对象上。
当检索到最后项目时我们采取复位enumerator的方式结束foreach ()以便foreach ()方法在立即再次调用的时候可以对同一集合运行。
为了对集合类实现foreach()方法,你必须完全隐藏Ienumerable或Ienumerator接口,如清单B所示。
为了执行forech你得需要一个集合类再加一个 Foreach 类的实例,此外还得加上一个存储枚举出的集合值的对象。显然,foreach 其实是普通的方法调用而非重复构造,因此我们必须在其内部编写一个while语句实现循环运行,但是,正如你在清单B中看到的那样这一实现比较困难。
以嵌套的方式采用Foreach类可能会出现问题,因为enumerator可以在层次更深的循环内重写。为了解决这个问题,你需要实现Foreach类的两个实例:一个用于外循环,一个用于内循环,如清单C.所示。
注意,集合的类型不要过于具体化,因此我们采用了数组和数组列表。我们还可能用到堆栈、队列、哈希表或其他.NET框架类库的集合类。
如清单D所示加入主函数之后程序的输出结果如图A所示。
图A
清单D的程序执行结果
foreach是C#和Visual Basic.NET语言中一种强大的.NET集合循环构造方式。可惜从受管C++语言中没有它的影子。这篇文章向你提供了实现自己版本foreach 的方法,之后你自然知道如何在自己的程序中实现它。