枚舉類型
「符號名稱/值」配對
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
}
GetValues:返回枚舉類型中符號的數組
Parse/TryParse:將符號轉換為枚舉類型的實例
IsDefined:判斷數值對於枚舉類型是否合法
查找區分大小寫
內部使用了反射,速度很慢
枚舉類型在調用IsDefined的同一程序集中定義才可使用
但可以使用「擴展方法」為枚舉類型提供方法
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#編譯器把枚舉類型視為基元類型,所以可用許多操作符(==、!=、>、<等等)來操縱枚舉類型的實例
所有這些操作符實際作用於每個枚舉類型實例內部的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:按位或
參考書目
- 《CLR via C#》(第4版) Jeffrey Richter