C# 枚举(Enum)
定义、底层类型、`[Flags]`、以及枚举与字符串互转。
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=9The 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| Operation | Syntax | Meaning |
|---|---|---|
| 组合 | 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.
定义与使用
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默认底层类型是 int。要存进数据库的 tinyint 列或做网络协议时,显式声明 : byte / : short 能省空间也避免转换。
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| 操作 | 写法 | 含义 |
|---|---|---|
| 组合 | a | b | 加上 |
| 判断 | a.HasFlag(b) | 是否包含 |
| 移除 | a &= ~b | 去掉 |
| 交集 | a & b | 共同部分 |
[Flags] 的值必须是 2 的幂(1, 2, 4, 8...),否则按位组合会串位。None = 0 是惯例,表示「没有任何标志」。枚举 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
已支付枚举的价值不只是可读性:它把「合法取值」变成类型约束,参数写 Status 就传不进 99(除非强转)。这是 C# 比用 int 常量强的地方。