備註
此內容經Pearson Education, Inc.授權從架構設計指導方針:可重複使用 .NET 程式庫的慣例、習慣用語與範式 (第2版)轉載。 該版於2008年出版,該書自那以後已於 第三版全面修訂。 此頁面的某些資訊可能已過期。
專為操作具共同特性的一組物件而設計的任何類型都可以視為集合。 實作 IEnumerable 或 IEnumerable<T> 這類類型幾乎一律適用,因此在本節中,我們只會考慮那些實作其中一個或兩個介面的類型來作為集合。
❌ 請勿在公用 API 中使用弱型別集合。
代表集合項目的所有傳回值和參數類型應該是確切的項目類型,而不是其任何基底類型(這只適用於集合的公用成員)。
❌ 請勿在公用 API 中使用 ArrayList 或 List<T> 。
這些類型是設計成用於內部實作的數據結構,而不是在公用 API 中使用。
List<T>
針對效能和性能進行優化,但以犧牲 API 的整潔性和靈活性為代價。 例如,如果您傳回 List<T>
,則當用戶端程式代碼修改集合時,您將永遠無法接收通知。 此外,List<T>
也會公開許多成員,例如 BinarySearch,在許多情境下不具意義或不適用。 下列兩節描述專為在公用 API 中使用的類型(抽象概念)。
❌ 請勿在公用 API 中使用 Hashtable
或 Dictionary<TKey,TValue>
。
這些類型是設計用於內部實作的數據結構。 公用 API 應該使用 IDictionary、 IDictionary <TKey, TValue>
或實作一或兩個介面的自定義型別。
❌ 請勿使用 IEnumerator<T>、 IEnumerator或任何其他實作這些介面的型別,但方法的 GetEnumerator
傳回型別除外。
無法將從非GetEnumerator
方法返回列舉器的類型與foreach
語句一起使用。
❌ 不要在相同類型上同時實作IEnumerator<T>
和IEnumerable<T>
。 同樣適用於非泛型介面 IEnumerator
和 IEnumerable
。
集合參數
✔️ 請盡可能使用最不專門化的類型用作參數類型。 大部分採用集合做為參數的成員都會使用 IEnumerable<T>
介面。
❌ 請避免只使用 ICollection<T> 或 ICollection 作為參數來存取 Count
屬性。
相反地,請考慮使用 IEnumerable<T>
或 IEnumerable
,並動態檢查物件是否實作 ICollection<T>
或 ICollection
。
集合屬性和傳回值
❌ 請勿提供可設定的集合屬性。
使用者可以先清除集合,然後新增新內容,以取代集合的內容。 如果取代整個集合是常見的案例,請考慮在集合上提供 AddRange
方法。
✔️ 請針對代表讀取/寫入集合的屬性或傳回值使用 Collection<T>
或 的子類別 Collection<T>
。
如果 Collection<T>
不符合某些需求(例如集合不得實作 IList),請實作 IEnumerable<T>
、ICollection<T>
或 IList<T> 來使用自定義集合。
✔️ 請使用ReadOnlyCollection<T>、其子類別ReadOnlyCollection<T>
,或在少數情況下使用IEnumerable<T>
,來表示唯讀集合的屬性或傳回值。
一般而言,偏好 ReadOnlyCollection<T>
。 如果不符合某些需求(例如集合不能實作 IList
),請通過實作 IEnumerable<T>
、ICollection<T>
或 IList<T>
來使用自定義集合。 如果您實作自訂唯讀集合,請實 ICollection<T>.IsReadOnly
作 以傳回 true
。
如果您確定唯一想要支援的情況是僅正向迭代,那麼可以直接使用 IEnumerable<T>
。
✔️ 請考慮使用泛型基底集合的子類別,而不是直接使用集合。
這允許使用更好的名稱,以及新增那些不存在於基礎集合類型的輔助成員。 這特別適用於高階 API。
✔️ 考慮從常用的方法和屬性返回 Collection<T>
或 ReadOnlyCollection<T>
的子類別。
這可讓您新增協助程式方法,或在未來變更集合實作。
✔️ 如果儲存在集合中的專案具有唯一索引鍵(名稱、標識符等),請考慮使用索引鍵集合。 鍵集合是可由整數和鍵進行編索的集合,通常透過繼承自 KeyedCollection<TKey,TItem>
來實作。
索引鍵集合通常具有較大的記憶體使用量,如果記憶體額外負荷超過擁有密鑰的優點,則不應該使用。
❌ 請勿從集合屬性或從傳回集合的方法傳回 Null 值。 請改為傳回空集合或空陣列。
一般規則是,Null 和空集合(0 個項目)或陣列應該同等對待。
快照集與動態集合
代表某個時間點狀態的集合稱為快照集集合。 例如,包含從資料庫查詢傳回之數據列的集合會是快照集。 一律代表目前狀態的集合稱為即時集合。 例如,ComboBox
的項目集合是動態集合。
❌ 請勿從屬性傳回快照集集合。 屬性應該會傳回動態集合。
屬性獲取器應該是非常輕量級的操作。 傳回快照需要在 O(n) 作業中建立一個內部集合的複本。
✔️ DO 使用快照集合或即時 IEnumerable<T>
(或其子類型)來表示容易變動的集合(亦即可以在不明確修改集合的情況下變更的集合)。
一般而言,代表共用資源的所有集合(例如目錄中的檔案)都是不穩定的。 除非實作只是單向的列舉器,否則這類集合要作為動態集合實作是非常困難或不可能的。
在陣列和集合之間選擇
✔️ DO 偏好集合而不是陣列。
集合可提供對內容的更多控制、隨著時間演進,而且更容易使用。 此外,不建議針對唯讀情境使用陣列,因為複製陣列的成本是令人望而卻步的。 可用性研究顯示,有些開發人員使用以集合為基礎的 API 感覺更舒服。
不過,如果您正在開發低階 API,最好是針對讀寫場景使用陣列。 陣列的記憶體占用較小,有助於減少工作集大小,而且存取陣列中的元素速度較快,因為其已由執行時期優化。
✔️ 請考慮在低階 API 中使用陣列,以將記憶體耗用量降至最低,並將效能最大化。
✔️ 請使用位元組陣列,而非位元組集合。
❌ 請勿針對屬性使用陣列,若屬性每次呼叫屬性 getter 時都必須傳回新的陣列(例如內部陣列的複本)。
實作自定義集合
✔️ 請考慮在設計新集合時從 Collection<T>
、ReadOnlyCollection<T>
或 KeyedCollection<TKey,TItem>
繼承。
✔️ 在設計新系列時,請實施 IEnumerable<T>
。 請考慮在合適的地方實作 ICollection<T>
或甚至 IList<T>
。
實作這類自定義集合時,請盡可能遵循由 Collection<T>
和 ReadOnlyCollection<T>
所建立的 API 模式。 也就是說,明確實作相同的成員,並將參數命名為類似這兩個集合的名稱,等等。
✔️ 如果集合通常會傳遞至採用這些介面做為輸入的 API,請考慮實作非泛型集合介面 (IList
和 ICollection
) 。
❌ 避免在與集合概念無關的複雜 API 類型上實作集合介面。
❌ 請勿繼承自非泛型基底集合,例如 CollectionBase
。 請改用 Collection<T>
、ReadOnlyCollection<T>
和 KeyedCollection<TKey,TItem>
。
命名自訂集合
集合(IEnumerable
的實作類型)主要是基於兩個原因而建立:(1)創建具備結構特定操作的新資料結構,且效能特性通常不同於現有的資料結構(例如,List<T>、LinkedList<T>、Stack<T>),以及(2)創建一個專門的集合來保存一組特定的專案(例如,StringCollection)。 數據結構最常用於應用程式和連結庫的內部實作中。 特製化集合主要是在 API 中公開(作為屬性和參數類型)。
✔️ 請在實作IDictionary
或IDictionary<TKey,TValue>
的抽象概念名稱中使用「Dictionary」後綴。
✔️ 請在實作 IEnumerable
(或其任何子系)並表示項目清單的類型名稱中使用「Collection」後綴。
✔️ 請針對自訂數據結構使用適當的數據結構名稱。
❌ 請避免在集合抽象概念的名稱中使用任何隱含特定實作的後綴,例如 “LinkedList” 或 “Hashtable”。
✔️ 請考慮在集合名稱前面加上項目類型的名稱。 例如,儲存型別 Address
(實作 IEnumerable<Address>
)的集合專案應該命名為 AddressCollection
。 如果專案類型是介面,則可以省略項目類型的 「I」 前置詞。 因此,一個由IDisposable項目組成的集合可以稱為DisposableCollection
。
✔️ 如果架構中可能會加入或已經存在對應的可寫入集合,請考慮在唯讀集合的名稱中使用 「ReadOnly」 前置詞。
例如,字串的唯讀集合應該稱為 ReadOnlyStringCollection
。
© 2005年、2009年Microsoft公司部分。 保留所有權利。
經 Pearson Education, Inc. 許可重新刊登自 Krzysztof Cwalina 和 Brad Abrams 所著的 架構設計指導方針: 可重複使用的 .NET 程式庫慣例、慣用語和模式,第 2 版,2008 年 10 月 22 日由 Addison-Wesley Professional 發行,作為 Microsoft Windows 開發系列的一部分。