共用方式為


集合方針

注意

此內容是由 Pearson Education, Inc. 授權轉載自架構設計指導方針:可重複使用 .NET 程式庫的慣例、慣用語和模式,第 2 版。 該版於 2008 年出版,該書自那以後已於第三版進行了全面修訂。 此頁面上的某些資訊可能已過期。

任何特別設計用來操作具有一些通用特性之物件群組的型別,都可以視為集合。 這幾乎一律適用於這類型別實作 IEnumerableIEnumerable<T>,因此在本節中,我們只會考慮實作其中一個或兩個介面的型別成為集合。

❌ 請勿在公用 API 中使用弱式型別集合。

代表集合項目的所有傳回值和參數型別都應該是確切的項目類型,而不是其任何基底類型 (這只適用於集合的公用成員)。

❌ 請勿在公用 API 中使用 ArrayListList<T>

這些型別是設計成用於內部實作的資料結構,而不是在公用 API 中使用。 List<T> 針對效能和電源最佳化,代價是 API 和彈性的清理。 例如,如果您傳回 List<T>,當用戶端程式代碼修改集合時,您無法接收通知。 此外,List<T> 也會公開許多成員,例如 BinarySearch,在許多案例中都不實用或不適用。 下列兩節說明專為在公用 API 中使用而設計的型別 (抽象)。

❌ 請勿在公用 API 中使用 HashtableDictionary<TKey,TValue>

這些型別是設計成用於內部實作的資料結構。 公用 API 應該使用 IDictionaryIDictionary <TKey, TValue>,或實作一個或兩個介面的自訂型別。

❌ 請勿使用 IEnumerator<T>IEnumerator,或實作任一介面的其他任何型別,除非是 GetEnumerator 方法的傳回型別。

GetEnumerator 以外的方法傳回列舉值的型別,不能與 foreach 陳述式搭配使用。

❌ 請勿在相同型別上實作 IEnumerator<T>IEnumerable<T>。 這同樣適用於非泛型介面 IEnumeratorIEnumerable

集合參數

✔️ 請盡可能使用最小特製化型別作為參數型別。 大部分採用集合作為參數的成員都會使用 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 項目的集合是即時集合。

❌ 請勿從屬性傳回快照集集合。 屬性應該會傳回即時集合。

屬性 getter 應該是非常輕量的作業。 傳回快照集需要在 O(n) 作業中建立內部集合的複本。

✔️ 請務必使用快照集集合或即時 IEnumerable<T> (或其子型別) 來代表動態集合 (亦即可以變更而不明確修改集合)。

一般而言,代表共用資源的所有集合 (例如目錄中的檔案) 都是動態。 除非實作只是順向列舉程式,否則這類集合很難或無法實作為即時集合。

在陣列和集合之間選擇

✔️ 偏好使用集合而非陣列。

集合提供對內容的更多控制權,可隨著時間演進,而且更容易使用。 此外,不建議針對唯讀案例使用陣列,因為複製陣列的成本是禁止的。 可用性研究顯示,有些開發人員更熟悉使用以集合為基礎的 API。

不過,如果您要開發低階 API,最好是針對讀寫案例使用陣列。 陣列的記憶體使用量較小,有助於減少工作集,而且陣列中的元素存取速度較快,因為已由執行階段最佳化。

✔️ 請考慮在低階 API 中使用陣列,以將記憶體耗用量降至最低,並將效能最大化。

✔️ 請使用位元組陣列,而不是位元組集合。

❌ 如果每次呼叫屬性 getter 時,屬性必須傳回新的陣列 (例如內部陣列的複本),請勿使用屬性的陣列。

實作自訂集合

✔️ 請考慮在設計新集合時繼承自 Collection<T>ReadOnlyCollection<T>KeyedCollection<TKey,TItem>

✔️ 設計新集合時,請實作 IEnumerable<T>。 請考慮實作 ICollection<T> 或甚至是 IList<T> (如果合理的話)。

實作這類自訂集合時,請盡可能遵循 Collection<T>ReadOnlyCollection<T> 所建立的 API 模式。 也就是說,明確實作相同的成員、將參數命名為類似這兩個集合的名稱等等。

✔️ 如果集合通常會傳遞至採用這些介面作為輸入的 API,請考慮實作非泛型集合介面 (IListICollection)。

❌ 請避免在具有與集合概念無關之複雜 API 的型別上,實作集合介面。

❌ 請勿從非泛型基底集合繼承,例如 CollectionBase。 請改用 Collection<T>ReadOnlyCollection<T>KeyedCollection<TKey,TItem>

命名自訂集合

集合 (實作 IEnumerable 的型別) 主要針對以下兩個原因建立:(1) 建立新的資料結構,具有結構特定作業且通常有與現有資料結構不同的效能特性 (例如,List<T>LinkedList<T>Stack<T>),以及 (2) 建立特殊化集合來保存一組特定項目 (例如,StringCollection)。 資料結構最常用於應用程式和程式庫的內部實作。 特殊化集合主要是在 API 中公開 (作為屬性和參數型別)。

✔️ 請務必在實作 IDictionaryIDictionary<TKey,TValue> 的抽象概念名稱中使用 "Dictionary" 尾碼。

✔️ 請務必在實作 IEnumerable (或其任何子系) 並代表項目清單的型別名稱中,使用 "Collection" 尾碼。

✔️ 請對自訂資料結構使用適當的資料結構名稱。

❌ 請避免在集合抽象名稱中,使用會表示特定實作的任何尾碼,例如 "LinkedList" 或 "Hashtable"。

✔️ 請考慮在集合名稱前面加上項目類型的名稱。 例如,儲存型別為 Address (實作 IEnumerable<Address>) 之項目的集合應該名為 AddressCollection。 如果項目類型是介面,則可以省略項目類型的 "I" 前置詞。 因此,IDisposable 項目的集合可以稱為 DisposableCollection

✔️ 如果架構中可能加入或已經存在對應的可寫入集合,請考慮在唯讀集合的名稱中使用 "ReadOnly" 前置詞。

例如,字串的唯讀集合應該稱為 ReadOnlyStringCollection

Portions © 2005, 2009 Microsoft Corporation. 著作權所有,並保留一切權利。

獲 Pearson Education, Inc. 的授權再版,從 Krzysztof Cwalina 和 Brad Abrams 撰寫,並在 2008 年 10 月 22 日由 Addison-Wesley Professional 出版,作為 Microsoft Windows Development Series 一部份的 Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition 節錄。

另請參閱