顯式列舉轉換 ((E)value) 允許在列舉類型與整數類型、不同列舉類型之間進行強制轉換。其本質是底層整數值的重新解讀,編譯器不進行語意驗證 (除非常數運算式)。理解轉換機制、Flags 列舉特性與陷阱,對正確處理狀態機、位標旗標與序列化至關重要。
enum Color : int { Red = 1, Green = 2, Blue = 4 } // 底層 int
enum Priority : byte { Low = 1, High = 2 } // 底層 byte
// 所有列舉轉換本質上:來源 → 底層類型 → 目標類型
// 編譯器不檢查值是否對應有效列舉成員 (非常數情況)
來源:sbyte, byte, short, ushort, int, uint, long, ulong, char (整數類型)
enum Status : int { None = 0, Active = 1, Inactive = 2 }
// 合法轉換 (值可能無對應成員)
Status s1 = (Status)1; // Active
Status s2 = (Status)999; // 999 (合法但危險!)
Status s3 = (Status)(-1); // -1 (合法)
// 類型匹配:整數類型需可隱含/顯式轉換為列舉底層類型
long big = 100;
// Status s4 = (Status)big; // 編譯錯誤:long → int 需顯式
Status s4 = (Status)(int)big; // 正確:雙重轉換
// char → 列舉 (Unicode 碼位)
Status s5 = (Status)'A'; // 65
目標:sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
enum Flags : uint { A = 1, B = 2, C = 4 }
// 列舉 → 整數 (隱含轉換至底層類型,其他需顯式)
uint u = (uint)Flags.A; // 1 (底層類型 uint)
int i = (int)Flags.A; // 1 (顯式轉換 uint → int)
byte b = (byte)Flags.C; // 4 (uint → byte,可能截斷)
long l = (long)Flags.B; // 2
// 浮點數/decimal (罕見但合法)
float f = (float)Flags.A; // 1.0f
decimal d = (decimal)Flags.C; // 4m
enum Color : int { Red = 1, Green = 2 }
enum Priority : int { Low = 1, High = 2 }
enum Status : byte { None = 0, Active = 1 }
// 同底層類型:直接重新解讀
Color c = (Color)Priority.High; // Color.Green (值 2)
// 不同底層類型:經由整數中介
Priority p = (Priority)(int)Color.Red; // Priority.Low (值 1)
Status s = (Status)(int)Color.Red; // Status.Active (值 1,byte 截斷)
// 底層機制:Color(int) → int → Priority(int) / Status(byte)
[Flags] enum Perm { None = 0, Read = 1, Write = 2, Exec = 4 }
// 組合旗標
Perm combined = Perm.Read | Perm.Write; // 值 3
// 整數轉換為 Flags 列舉
Perm p1 = (Perm)3; // Read | Write (語意正確)
Perm p2 = (Perm)5; // Read | Exec (語意正確)
Perm p3 = (Perm)7; // Read | Write | Exec
Perm p4 = (Perm)99; // 99 (無對應組合,但合法)
// HasFlag 檢查 (內部用位元 AND)
bool hasRead = p1.HasFlag(Perm.Read); // true
// 非 Flags 列舉轉換整數無組合語意
enum Simple { A = 1, B = 2 }
Simple s = (Simple)3; // 3 (非 A|B,單純值 3)
enum Small : byte { A = 1, B = 2 }
// 編譯時期常數:檢查範圍
// Small s1 = (Small)300; // CS0220: 常數 300 超出 byte 範圍 (0-255)
// Small s2 = (Small)(-1); // CS0220: 常數 -1 超出 byte 範圍
// 非常數:無編譯檢查
byte b = 300; // 編譯錯誤 (常數)
byte b2 = GetByte(); // 執行時期 300
Small s3 = (Small)b2; // 成功 (執行時期 44 = 300 % 256)
// 序列化:列舉 → 整數
int serialized = (int)status;
// 反序列化:整數 → 列舉 (需驗證)
Status deserialized = Enum.IsDefined(typeof(Status), value)
? (Status)value
: Status.None; // 預設值
// 或使用 TryParse (字串輸入)
Status parsed;
bool ok = Enum.TryParse(input, out parsed);
[Flags] enum Perm { R = 1, W = 2, X = 4 }
// 設定旗標
perm |= Perm.W; // perm = perm | Perm.W
// 清除旗標
perm &= ~Perm.W; // perm = perm & ~Perm.W
// 切換旗標
perm ^= Perm.X; // perm = perm ^ Perm.X
// 檢查旗標
bool canWrite = (perm & Perm.W) != 0; // 或 perm.HasFlag(Perm.W)
// 危險:用加減法操作旗標
// perm += Perm.W; // 錯誤:若已有 W,值變 4 (非預期)
[Flags] enum Bits : uint
{
Bit0 = 1 << 0, Bit1 = 1 << 1, Bit2 = 1 << 2,
// ... up to Bit31
Mask = 0xFFFFFFFF
}
// 32 位整數作為旗標容器
Bits flags = 0;
flags |= Bits.Bit5 | Bits.Bit10; // 設定第 5、10 位
bool bit5 = (flags & Bits.Bit5) != 0;
| 底層類型 | 範圍 | 大小 | 適用場景 |
|---|---|---|---|
byte | 0 ~ 255 | 1 位元組 | 旗標 ≤ 8 位、記憶體敏感 |
sbyte | -128 ~ 127 | 1 位元組 | 罕見,需負值旗標 |
short | -32768 ~ 32767 | 2 位元組 | 旗標 ≤ 16 位 |
ushort | 0 ~ 65535 | 2 位元組 | 旗標 ≤ 16 位 |
int (預設) | ±21 億 | 4 位元組 | 通用、旗標 ≤ 32 位 |
uint | 0 ~ 42 億 | 4 位元組 | Flags 列舉首選 (無符號位運算直覺) |
long | ±9 兆 | 8 位元組 | 旗標 > 32 位 |
ulong | 0 ~ 18 兆 | 8 位元組 | Flags 列舉 > 32 位首選 |
[Flags] — 啟用 HasFlag、ToString 組合顯示、序列化語意uint/ulong — 位運算語意最直覺,避免符號位干擾Enum.IsDefined — 或定義 None = 0 作為預設回退&/|/^/~ — 非加減法精通顯式列舉轉換的底層機制與 Flags 語意,能正確建模狀態、旗標與序列化協定,避免隱性資料損壞與邏輯錯誤。