C#筆記 – 枚舉和位標志
枚舉類型
-
「符號名稱/值」配對
-
public enum TimePeriod { Morning = 0, Afternoon = 1, Night = 2 }
-
-
類型安全
-
每個枚舉類型派生自System.Enum,System.Enum派生自System.ValueType,因此枚舉屬於值類型
-
枚舉類型內部不能定義任何方法/屬性/事件
- 編譯枚舉類型時,C#編譯器將每個符號轉換成類型的一個常量字段,以上面的TimePeriod枚舉為例,其內部工作方式是這樣的
-
public struct TimePeriod : System.Enum { //TimePeriod的符號和值定義 public const TimePeriod Morning = (TimerPeriod) 0; public const TimePeriod Afternoon = (TimerPeriod) 1; public const TimePeriod Night = (TimerPeriod) 2; public int value__; //包含TimePeriod變量的值,不能通過代碼直接引用 } -
簡單而言,枚舉類型只是一個結構,其中定義了一組常量字段和一個實例字段
- 常量字段會嵌入程序集的元數據中,可通過反射來訪問
- 因此,支持在運行時獲得與枚舉類型關聯的所有符號及其值/將字符串符號轉換成對應的數值
- 這些操作由System.Enum的靜態方法提供
-
GetUnderlyingType:返回用於容納一個枚舉類型的值的基礎類型
- 基礎類型默認為int,也可以聲明為其他的基元值類型
-
public enum EnumBasicType : ushort { Basic, Normal, Hard }
-
- 基礎類型默認為int,也可以聲明為其他的基元值類型
-
GetValues:返回枚舉類型中符號的數組
-
Parse/TryParse:將符號轉換為枚舉類型的實例
-
IsDefined:判斷數值對於枚舉類型是否合法
- 查找區分大小寫
- 內部使用了反射,速度很慢
- 枚舉類型在調用IsDefined的同一程序集中定義才可使用
-
- 這些操作由System.Enum的靜態方法提供
-
- 但可以使用「擴展方法」為枚舉類型提供方法
-
class Program { static void Main(string[] args) { TimePeriod tp = TimePeriod.Morning; Console.WriteLine(tp.IsMorning()); //True } } public static class TimePeriodExtension { public static bool IsMorning(this TimePeriod t) { return t == TimePeriod.Morning; } }
-
- 編譯枚舉類型時,C#編譯器將每個符號轉換成類型的一個常量字段,以上面的TimePeriod枚舉為例,其內部工作方式是這樣的
-
C#編譯器把枚舉類型視為基元類型,所以可用許多操作符(==、!=、>、<等等)來操縱枚舉類型的實例
- 所有這些操作符實際作用於每個枚舉類型實例內部的value__實例字段
-
枚舉類型通常與需要它的類同級
位標志
-
通常用枚舉類型來表示一組可以組合的位標志,如FileAttributes
-
namespace System.IO { [Flags] public enum FileAttributes { ReadOnly = 1, Hidden = 2, System = 4, Directory = 16, Archive = 32, Device = 64, Normal = 128, Temporary = 256, SparseFile = 512, ReparsePoint = 1024, Compressed = 2048, Offline = 4096, NotContentIndexed = 8192, Encrypted = 16384, IntegrityStream = 32768, NoScrubData = 131072 } }
-
-
定義用於標識位標志的枚舉類型時,應顯式為每個符號分配一個數值
- 每個符號都有單獨的一個位處於on狀態
-
應定義一個值為0的None符號
-
最好應用特性System.Flags/System.FlagsAttribute
- 檢測到Flags特性後,操作就不會把數值視為單獨的值,而是一組位標志,並根據操作對數值和枚舉定義的「符號/值」數進行「按位與」/「按位或」運算
- ToString:按位與
- Parse/TryParse:按位或
- 檢測到Flags特性後,操作就不會把數值視為單獨的值,而是一組位標志,並根據操作對數值和枚舉定義的「符號/值」數進行「按位與」/「按位或」運算
參考書目
- 《CLR via C#》(第4版) Jeffrey Richter