C# 枚举(Enum)

定义、底层类型、`[Flags]`、以及枚举与字符串互转。

Beginner
Key Points枚举是具名的整数常量;`[Flags]` 让它能按位组合。

定义与使用

C#
enum Status
{
    Pending,        // 0
    Paid,           // 1
    Shipped,        // 2
    Cancelled = 9   // 手动指定
}

var s = Status.Paid;
Console.WriteLine(s);
Console.WriteLine((int)s);
Console.WriteLine(s == Status.Paid);

// 字符串转枚举
var parsed = Enum.Parse<Status>("Shipped");
Console.WriteLine(parsed);

// 安全解析
if (Enum.TryParse<Status>("Nope", out var bad))
{
    Console.WriteLine(bad);
}
else
{
    Console.WriteLine("解析失败");
}
Output
Paid
1
True
Shipped
解析失败

底层类型

C#
enum Small : byte
{
    A = 1,
    B = 2
}

enum Large : long
{
    Big = 9_000_000_000
}

Console.WriteLine(sizeof(byte));
Console.WriteLine((byte)Small.B);
Console.WriteLine((long)Large.Big);

// 遍历所有值
foreach (var v in Enum.GetValues<Status>())
{
    Console.WriteLine($"{v}={(int)v}");
}
Output
1
2
9000000000
Pending=0
Paid=1
Shipped=2
Cancelled=9

The underlying type is int by default. When storing in a tinyint column or a wire protocol, declare : byte / : short to save space and avoid casts.

Flags 位标志

C#
[Flags]
enum Permission
{
    None    = 0,
    Read    = 1 << 0,      // 1
    Write   = 1 << 1,      // 2
    Delete  = 1 << 2,      // 4
    Admin   = Read | Write | Delete   // 7
}

var p = Permission.Read | Permission.Write;
Console.WriteLine(p);
Console.WriteLine((int)p);
Console.WriteLine(p.HasFlag(Permission.Read));
Console.WriteLine(p.HasFlag(Permission.Delete));

// 去掉某个权限
p &= ~Permission.Write;
Console.WriteLine(p);

// 加上
p |= Permission.Delete;
Console.WriteLine(p);
Output
Read, Write
3
True
False
Read
Read, Delete
OperationSyntaxMeaning
组合a | b加上
判断a.HasFlag(b)是否包含
移除a &= ~b去掉
交集a & b共同部分
[Flags] values must be powers of two (1, 2, 4, 8...), or the bit combinations collide. None = 0 is conventional for "no flags".

枚举 vs 常量

C#
// 反例:魔法数字
void SetStatus(int s) { }
SetStatus(2);              // 2 是什么?

// 正例:枚举,调用处自解释
void SetStatus(Status s) { }
SetStatus(Status.Shipped);

// 枚举还能用 switch 穷尽检查
string Describe(Status s) => s switch
{
    Status.Pending => "待支付",
    Status.Paid => "已支付",
    Status.Shipped => "已发货",
    Status.Cancelled => "已取消",
    _ => "未知"
};

Console.WriteLine(Describe(Status.Paid));
Output
已支付

Enums do more than readability: they turn legal values into a type constraint. A Status parameter rejects 99 without an explicit cast — that is where they beat int constants.

Friends & Partners