1.尋訪collection元素
無論物件類型是陣列,串列...資料結構都會用到尋訪原素這個操作,於是.NET Framework將這些基本共通操作定義於兩個Interface中,
使我扪可以用同一組方法來操作各種不同collection物件。
這兩個Interface就是:
a. IEnumerable
b. IEnumerator
2.IEnumerable and IEnumerator
IEnumerator定義了一組列舉器的巡覽操作,這操作是read only(並不會改變目前物件的內容),而且巡覽方向是單一的(只能取下一個元素)。
定義如下:
public interface IEnumerator
{
object Current{ get; } //傳回目前的元素
bool MoveNext(); //移至下一個元素,若傳回false則表示沒有下一個元素
void Reset(); //重新指向第一個元素
}
不過 collection 通常不實做IEnumerator,而是透過實做IEnumerable介面來提供列舉器。
定義如下:
public interface IEnumerable
{
IEnumerator GetEnumerator(); //取得列舉器
}
如上只定義一個GetEnumerator()方法,傳回IEnumerator 物件,所以IEnumerable基本上扮演提供列舉器之角色,
而collection類型(array,list...)都有實做IEnumerable介面,故它們(Array,List....)都是列舉器的提供者。
example(示範如何透過 IEnumerator 尋訪collection中每一個元素)
note:
1.IEnumerator enumrt = fruits.GetEnumerator();
之所以可以通過編譯是因為C#Array都繼承System.Array類別,而System.Array類別都有實做IEnumerable介面,故可以呼叫GetEnumerator()方法。
2.enumrt.Current傳回型別是object,故須手動轉型。
3.其實可以用foreach來取代,因為froeach可以尋訪任何"可列舉的"物件,符合以下任一條件都稱為符合可列舉之物件:
a.實做IEnumerable or IEnumerator
b.回傳之型別有實做IEnumerator or GetEnumerator<T>
ex.
string[] fruits = {"Apple","Banana","Orange"};
froeach(var item in fruits)
{
response.write(item);
}
3.IEnumerable<T> and IEnumerator<T>
定義列舉操作也有泛型版本,且泛型版本比非泛型更常用也更方便(不用手動轉型)。
底下為此兩個泛型介面之定義:
public interface IEnumerable<out T> : IEnumerable
{
IEnumerator<T> GetEnumerator(); // 取得列舉器
}
public interface IEnumerator<out T> : IDisposable , IEnumerator
{
T Current{ get; }
}
note:
1.泛型參數T前有個out,out代表告訴編譯器,型別參數T在此介面中只能用於輸出(方法回傳值),不能當成輸入參數用。
2.GetEnumerator方法在呼叫時不需要,也不可以傳入泛型參數T,但注意其回傳型別仍為IEnumerator<T>。
IEnumerator<string> enumrt = fruits.GetEnumerator<string>();
上面這行編譯會失敗,因為呼叫GetEnumerator方法不需要傳入泛型型別。
解法: 把fruits陣列手動轉成IEnumerable<string>,如此便可以呼叫GetEnumerator方法,來取得泛型版本的IEnumerator<string>物件。
example: