内容摘要 -
C# foreach 语句用于循环访问可枚举 (enumerable) 集合的元素。为了成为可枚举的类型,集合必须具
有返回枚举器 (enumerator) 的无参数的 GetEnumerator 方法。一般而言,枚举器不易实现,但是通过
使用迭代器可以显著简化该任务。
迭代器 (iterator) 是一个产生 (yield) 有序值序列的语句块。迭代器与普通语句块的区别在于迭代器存在
一个或多个 yield 语句:
yield return 语句产生迭代的下一个值。
yield break 语句指示迭代完成。
只要函数成员的返回类型是枚举器接口 (enumerator interface) 之一或可枚举接口 (enumerable interface)
之一,迭代器就可用作该函数成员的函数体:
全文 -
C# 2.0语言规范讲义 - 迭代器
C# foreach 语句用于循环访问可枚举 (enumerable) 集合的元素。为了成为可枚举的类型,集合必须具
有返回枚举器 (enumerator) 的无参数的 GetEnumerator 方法。一般而言,枚举器不易实现,但是通过
使用迭代器可以显著简化该任务。
迭代器 (iterator) 是一个产生 (yield) 有序值序列的语句块。迭代器与普通语句块的区别在于迭代器存在
一个或多个 yield 语句:
yield return 语句产生迭代的下一个值。
yield break 语句指示迭代完成。
只要函数成员的返回类型是枚举器接口 (enumerator interface) 之一或可枚举接口 (enumerable interface)
之一,迭代器就可用作该函数成员的函数体:
枚举器接口为 System.Collections.IEnumerator和从
System.Collections.Generic.IEnumerator<T>构造的类型。
可枚举接口为 System.Collections.IEnumerable和从
System.Collections.Generic.IEnumerable<T>构造的类型。
迭代器并非一种成员,而是一种实现函数成员的手段,了解这一点很重要。通过迭代器实现的成员能够
被其他可能使用也可能不使用迭代器实现的成员重写或重载。
下面的 Stack<T> 类使用一个迭代器实现其 GetEnumerator 方法。该迭代器以自顶向下的顺序枚举堆
栈的元素。
using System.Collections.Generic;
public class Stack<T>: IEnumerable<T>
{
T[] items;
int count;
public void Push(T data) {...}
}
public T Pop() {...}
public IEnumerator<T> GetEnumerator() {
for (int i = count – 1; i >= 0; --i) {
yield return items[i];
}
}
GetEnumerator 方法的存在使得 Stack<T> 成为可枚举类型,这样,我们就可以在 foreach 语句中使
用 Stack<T> 的实例。下面的示例将值 0 至 9 推入一个整数堆栈,然后使用 foreach 循环按自顶向下
的顺序显示这些值。
using System;
class Test
{
static void Main() {
Stack<int> stack = new Stack<int>();
for (int i = 0; i < 10; i++) stack.Push(i);
foreach (int i in stack) Console.Write("{0} ", i);
Console.WriteLine();
}
}
该示例的输出为:
9 8 7 6 5 4 3 2 1 0
foreach 语句隐式调用集合的无参数 GetEnumerator 方法获得枚举器。一个集合只能定义一个这样的
无参数 GetEnumerator 方法,但是可以有多种枚举方式以及多种通过参数控制枚举的方式。在这种情
况下,集合可以使用迭代器实现多个返回可枚举接口类型之一的属性或方法。例如,Stack<T> 可引入
IEnumerable<T> 类型的两个新属性 TopToBottom 和 BottomToTop:
using System.Collections.Generic;
public class Stack<T>: IEnumerable<T>
{
T[] items;
int count;
public void Push(T data) {...}
public T Pop() {...}
public IEnumerator<T> GetEnumerator() {
for (int i = count – 1; i >= 0; --i) {
yield return items[i];
}
}
public IEnumerable<T> TopToBottom {
get {
return this;
}
}
public IEnumerable<T> BottomToTop {
get {
for (int i = 0; i < count; i++) {
yield return items[i];
}
}
}
}
TopToBottom 属性的 get 访问器直接返回 this,因为该堆栈本身是可枚举的。BottomToTop 属性返
回一个使用 C# 迭代器实现的可枚举接口类型。下面的示例显示如何使用这两个属性以任一顺序枚举堆
栈元素:
using System;
class Test
{
static void Main() {
Stack<int> stack = new Stack<int>();
for (i
|