HOW TO:使用 foreach 存取集合類別 (C# 程式設計手冊)
更新:2007 年 11 月
下列程式碼範例說明如何撰寫可搭配 foreach 使用的非泛型集合類別。這是一個從字串中取出語彙基元的類別,類似於 C 執行階段函式 strtok_s。
注意事項: |
---|
此範例所呈現的建議作法,只適用於無法使用泛型集合類別的情況。在 C# 語言和 .NET Framework 的 2.0 (含) 以後版本中有支援泛型。如需如何實作支援 IEnumerable<T> 之型別安全泛型集合類別的範例,藉此避免本主題稍後討論的問題,請參閱 HOW TO:建立泛型清單的 Iterator 區塊 (C# 程式設計手冊)。 |
在下列範例中,Tokens 會將 "This is a sample sentence." 這個句子分成多個語彙基元 (使用 ' ' 和 '-' 做為分隔符號),並以 foreach 陳述式列舉這些語彙基元:
Tokens f = new Tokens("This is a sample sentence.", new char[] {' ','-'});
foreach (string item in f)
{
System.Console.WriteLine(item);
}
Tokens 在內部使用一個陣列,此陣列本身實作 IEnumerator 和 IEnumerable。這個程式碼範例也可以使用陣列的列舉方法當做本身的方法,但這樣會失去此範例的目的。
在 C# 中,集合類別不一定需要繼承自 IEnumerable 和 IEnumerator,才能與 foreach 相容。只要類別具有必要的 GetEnumerator、MoveNext、Reset 和 Current 成員,就可以使用 foreach。省略介面的優點是,您可以將 Current 的傳回型別定義得比 Object 更明確,進而提供型別安全。
例如,從本主題前面的範例程式碼開始,變更下列幾行:
// No longer inherits from IEnumerable:
public class Tokens
// Doesn't return an IEnumerator:
public TokenEnumerator GetEnumerator()
// No longer inherits from IEnumerator:
public class TokenEnumerator
// Type-safe: returns string, not object:
public string Current
這時由於 Current 傳回的是字串,所以當 foreach 陳述式中使用了不相容的型別時,編譯器便可偵測出來:
// Error: cannot convert string to int:
foreach (int item in f)
省略 IEnumerable 和 IEnumerator 的缺點是,集合類別再也不能與其他 Common Language Runtime 相容語言的 foreach 陳述式 (或對等用法) 交互操作。
您可以藉由繼承自 IEnumerable 和 IEnumerator,並使用明確介面實作,以此結合兩者的優點,不但可有 C# 中的型別安全,又能與其他 Common Language Runtime 相容語言互通,如下範例。
範例
using System.Collections;
// Declare the Tokens class:
public class Tokens : IEnumerable
{
private string[] elements;
Tokens(string source, char[] delimiters)
{
// Parse the string into tokens:
elements = source.Split(delimiters);
}
// IEnumerable Interface Implementation:
// Declaration of the GetEnumerator() method
// required by IEnumerable
public IEnumerator GetEnumerator()
{
return new TokenEnumerator(this);
}
// Inner class implements IEnumerator interface:
private class TokenEnumerator : IEnumerator
{
private int position = -1;
private Tokens t;
public TokenEnumerator(Tokens t)
{
this.t = t;
}
// Declare the MoveNext method required by IEnumerator:
public bool MoveNext()
{
if (position < t.elements.Length - 1)
{
position++;
return true;
}
else
{
return false;
}
}
// Declare the Reset method required by IEnumerator:
public void Reset()
{
position = -1;
}
// Declare the Current property required by IEnumerator:
public object Current
{
get
{
return t.elements[position];
}
}
}
// Test Tokens, TokenEnumerator
static void Main()
{
// Testing Tokens by breaking the string into tokens:
Tokens f = new Tokens("This is a sample sentence.", new char[] {' ','-'});
foreach (string item in f)
{
System.Console.WriteLine(item);
}
}
}
/* Output:
This
is
a
sample
sentence.
*/