Iterator:枚舉器
如果你正在創建一個表現和行為都類似於集合的類,允許類的用戶使用foreach語句對集合中的成員進行枚舉將會是很方便的。這在C# 2.0中比 C# 1.1更容易實現一些。作為演示,我們先在 C# 1.1中為一個簡單的集合添加枚舉,然後我們修改這個范例,使用新的C#2.0 枚舉構建方法。
我們將以創建一個簡單化的List Box作為開始,它將包含一個8字符串的數組和一個整型,這個整型用於記錄數組中已經添加了多少字符串。構造函數將對數組進行初始化並使用傳遞進來的參數填充它。
public ListBox(params string[] initialStrings)
{
strings = new String[8];
foreach (string s in initialStrings)
{
strings[ctr++] = s;
}
}
除此以外,ListBox類還需要一個Add方法(進行添加 string 的操作) 和 一個返回數組中字符串個數的方法。
public void Add(string theString)
{
strings[ctr] = theString;
ctr++;
}
public int GetNumEntrIEs()
{
return ctr;
}
NOTE:實際開發中,通常使用ArrayList,而不是固定大小的數組。在這裡為了程序簡單就沒有做數組下標越界的檢測。
從感覺上看,ListBox像是一個集合,如果可以使用集合中通常使用的 foreach 循環來獲取listBox中的所有字符串將會是非常便利的。如此的話,可以這樣書寫代碼:
ListBox lb = new ListBox("a", "b", "c", "d", "e", "f", "g", "h");
foreach (string s in lb) {
Console.WriteLine(s);
}
但是,會得到這樣一個錯誤:
“Iterator.ListBox”不包含“GetEnumerator”的公共定義,因此 foreach 語句不能作用於“Iterator.ListBox”類型的變量
想要使用foreach語句,還必須實現IEnumerable 接口。
這個接口只要求實現一個方法: GetEnumerator。這個方法必須返回一個實現了IEnumerator 接口的對象。除此以外,我們需要返回的這個對象不僅實現了IEnumerator,而且知道如何枚舉ListBox對象。你將需要創建一個 ListBoxEmunerator(在下面描述):
NOTE: IEnumerable 和 IEnumerator 是不同的接口,請不要搞混了。
public IEnumerator GetEnumerator()
{
return new ListBoxEnumerator();
}
現在,ListBox 可以使用 foreach 循環了:
ListBox lbt = new ListBox("Hello", "World");
lbt.Add("Who");
lbt.Add("Is");
lbt.Add("John");
lbt.Add("Galt");
foreach (string s in lbt)
{
Console.WriteLine("Value: {0}", s);
}
先是實例化這個ListBox ,並初始了兩個字符串,隨後又添加了四個。foreach循環接受ListBox實例,並且迭代它,依次返回字符串。輸出是:
Hello
World
Who
Is
John
Galt
實現 IEnumerator 接口
注意到ListBoxEnumerator不僅需要實現IEnumerator接口,對於ListBox類它也需要一些特別了解;特別是,它必須可以獲得ListBox的字符串數組並且遍歷其所包含的字符串。IEnumerable 類和與其相關的 IEnumerator類之間的關系有一點微妙。實現IEnumerator接口的最好辦法是在IEnumerable類裡創建一個嵌套的IEnumerator類。
public class ListBox : IEnumerable
{
// 嵌套的私有ListBoxEnumerator類實現
private class ListBoxEnumerator : IEnumerator
{
// 代碼實現...
}
// ListBox類的代碼...
}
注意ListBoxEnumerator需要對它所嵌入的ListBox類的一個引用。你可以通過ListBoxEnumerator的構造函數來傳遞。