列舉設計
注意
此內容是由 Pearson Education, Inc. 授權轉載自架構設計指導方針:可重複使用 .NET 程式庫的慣例、慣用語和模式,第 2 版。 該版於 2008 年出版,該書自那以後已於第三版進行了全面修訂。 此頁面上的某些資訊可能已過期。
列舉是一種特殊的實值型別。 列舉有兩種:簡單列舉和旗標列舉。
簡單列舉會保留一組小型且封閉的選項。 簡單列舉的常見範例是一組色彩。
旗標列舉的設計目的是支援列舉值的位元運算。 旗標列舉的常見範例是選項清單。
✔️ 請針對強型別參數、屬性和傳回值 (代表值集合) 使用列舉。
✔️ 請偏好使用列舉,而不是靜態常數。
❌ 請勿將列舉用於開啟集合 (例如作業系統版本、朋友的姓名等)。
❌ 請勿提供保留的列舉值,以供日後使用。
您一律可以在稍後階段將值新增至現有的列舉。 如需將值新增至列舉的詳細資訊,請參閱將值新增至列舉。 保留值只會干擾實際值的集合,而且通常會導致使用者錯誤。
❌ 避免公開只有一個值的列舉。
確保 C API 未來擴充性的常見作法是將保留參數新增至方法簽章。 這類保留參數可以表示為具有單一預設值的列舉。 該動作不應在受控 API 中完成。 方法多載允許在未來版本中新增參數。
❌ 請勿在列舉中包含 Sentinel 值。
雖然 Sentinel 值有時對架構開發人員有所幫助,但會對架構的使用者造成混淆。 這些值用來追蹤列舉的狀態,而不是列舉所代表集合中的其中一個值。
✔️ 請在簡單列舉上提供零的值。
請考慮呼叫類似 "None" 的值。如果這類值不適用於此特定列舉,則列舉的最常見預設值應指派為零的基礎值。
✔️ 請考慮使用 Int32 (大部分程式設計語言中的預設值) 為列舉的基礎類型,除非下列任一項成立:
列舉是旗標列舉,而且您有超過 32 個旗標,或預期未來會有更多旗標。
基礎類型必須不同於 Int32,以便更容易與預期不同大小列舉的非受控程式碼達成互通性。
較小的基礎類型會導致空間大幅節省。 如果您預期列舉主要用於控制流程的引數,則大小造成的差異有限。 如果是下列情況,節省大小可能會相當重要:
您預期列舉會當做非常頻繁具現化結構或類別中的欄位使用。
您預期使用者會建立大型陣列或列舉執行個體的集合。
您預期要序列化列舉的大量執行個體。
針對記憶體內部使用量,請注意受控物件一律會 DWORD
對齊,因此您實際上在執行個體中需要多個列舉或其他小型結構,以封裝較小的列舉,以便產生差異,因為總執行個體大小一律會四捨五入至 DWORD
。
✔️ 請使用複數名詞或名詞片語命名旗標列舉,並使用單數名詞或名詞片語命名簡單列舉。
❌ 請勿直接擴充 System.Enum。
System.Enum 是 CLR 用來建立使用者定義列舉的特殊類型。 大部分的程式設計語言都提供程式設計元素,可讓您存取這項功能。 例如,在 C# 中,會使用 enum
關鍵字來定義列舉。
設計旗標列舉
✔️ 請將 System.FlagsAttribute 套用至旗標列舉。 請勿將此屬性套用至簡單的列舉。
✔️ 請對旗標列舉值使用兩個乘冪,以便使用位元 OR 運算將其自由結合。
✔️ 請考慮為常用的旗標組合提供特殊列舉值。
位元運算是進階概念,對於簡單工作而言不應該是必要條件。 ReadWrite 是這類特殊值的範例。
❌ 請避免建立旗標列舉,其中某些值組合無效。
❌ 請避免使用零旗標列舉值,除非值代表「清除所有旗標」並適當地命名,如下一個指導方針所規定。
✔️ 請將旗標列舉的零值命名為 None
。 針對旗標列舉,值必須一律表示「清除所有旗標」。
將值新增至列舉
人員經常發現,在已出貨之後,您又需要將值新增至列舉。 從現有的 API 傳回新增值時,可能會發生應用程式相容性問題,因為撰寫不佳的應用程式可能無法正確處理新值。
✔️ 請考慮將值新增至列舉,儘管會有微小的相容性風險。
如果您有因列舉新增而造成應用程式不相容的實際資料,請考慮新增傳回新值和舊值的 API,並淘汰應該只會繼續傳回舊值的舊 API。 這可確保您現有的應用程式保持相容。
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 節錄。