程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 實現IEnumerable 和 IEnumerator使類型具備枚舉功能的注意

實現IEnumerable 和 IEnumerator使類型具備枚舉功能的注意

編輯:C#入門知識

實現IEnumerable接口的類,可以支持foreach循環遍歷對象的集合元素

IEnumerable:
IEnumerator GetEnumerator() 返回可循環訪問集合的枚舉數。
IEnumerator:
object Current 獲取集合中的當前元素。 bool MoveNext() 將枚舉數推進到集合的下一個元素。
如果枚舉數 成功地推進到下一個元素,則為 true;如果枚舉數越過集合的結尾,則為 false。 void Reset() 將枚舉數設置為其初始位置,該位置位於集合中第一個元 素之前。

 

背景知識

在現實應用中,對於集合以及枚舉這些集合的需求非常普遍, 因此在.NET中集合所依賴的接口被設計為公共的。想要實現對象的枚舉就必須繼承IEnumerable接口。
public interface IEnumerable
{
      public IEnumerator GetEnumerator();
}

它 只有一個成員:GetEnumerator方法。該方法返回一個實際的枚舉器(enumerator)對象。那麼要定義一個枚舉器就要必 須實現IEnumrator接口:
public interface IEnumerator
{
      public Boolean MoveNext();
      public Object Current { get; }
      public void Reset();
}

這裡我不想把MSDN上的解釋在重復一遍,我只是提出一個問題,也就是說如果我們希望一個類型支持 枚舉特性,那麼我們就必須還要額外定義一個輔助類型來實現IEnumerator的所有方法。這個輔助類型通常被定義為一個Nested class聲明在主類內部。這樣在實現的時候我們發現,在app調用GetEnumerator()方法時,我們需要構造一個輔助類型的實例作為返回值。 這時我們有兩種做法:

  1. 把主類型的數據當時的靜態快照,以復本的形式在輔助類型初始化時賦值給輔助類型實例 (enumerator)
  2. 把主類型的數據的引用傳遞給輔助類型,保證app訪問的實時更新的數據

這 的確提供了一定的靈活性給用戶, 在app想要枚舉某個實例的數據集合時,也可以有兩種方法:

  1. 使用各接口暴露的方法
  2. 使用foreach語句:foreach( type-identifier in expression ) { embedded-statement }

對於foreach,我想提兩句,要想使用它所必須滿足的條件:

  1. expression必須實現GetEnumerator()方法
  2. GetEnumerator() 放回的實例必須實現MoveNext()和Current兩個公共方法。

問題1:為什麼需要兩個接口,而不把Current, MoveNext和Reset成員都放到IEnumerable接口中?

答 案:采用這種間接的方式是為了提高靈活性。你可以利用IEnumerator來決定如何展示你想要暴露的內部數據給客戶。當然你可以在一個類型中同時實現 這兩個接口:class MyArrayData : IEnumerable, IEnumerator { ... };這樣可以節省了一些創建輔助類型從而帶來的CPU和Memory開銷。一般建議在如下情況時,使用這種結合的方法:

  1. 當 數據沒有存儲在系統已有的集合中,否則可以直接把集合的enumerator返回
  2. 當你的自定義的Enumerator需要做 出了移動游標和返回數據之外的其他操作

問題2:如果集合 中的數據是值類型,那麼有什麼性能上的考慮麼?

答案:由於值類型在傳入ArrayList這樣的集合容器中時,需要 box,在傳出的時候需要unbox。經過很多驗證,這種操作時非常耗時的。因此,我們可以在實現標准的枚舉方法的時候,可以在暴露一些自定義的 GetEnumerator, MoveNext和Current方法(其實, 標准的接口只是調用自定義的接口而已的一個wrapper方法)。這樣既可以在自己的方法中避免了不必要的裝箱和拆箱操作(用自定義方法,而不能使用 foreach語句),又可以被約定俗成的foreach句法所調用(當然,這種情況下就不能避免box和unbox了)。

    

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved