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

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

編輯:.NET實例教程

在現實應用中,對於集合以及枚舉這些集合的需求非常普遍, 因此在.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