C#枚举需显式设0值成员以防非法值,组合用[Flags]且2的幂赋值,扩展方法封装逻辑,反序列化须手动校验合法性。

直接用 enum 声明,然后当类型用就行;但不验证值合法性、不处理位组合、不加扩展方法,就只是“能跑”,不是“写对了”。
声明枚举时为什么必须显式设 0 值成员
因为 C# 允许隐式把 0 赋给任意枚举变量,哪怕它根本不在枚举列表里。比如:
enum GpioPort { GpioA = 1, GpioB, GpioC }
GpioPort p = (GpioPort)0; // 编译通过,但 p.ToString() 输出 "0",不是有效名称
这会导致 Enum.IsDefined(typeof(GpioPort), p) 返回 false,后续序列化、日志、UI 显示都可能出错。
- 始终让第一个成员值为
0(如None = 0、Unknown = 0) - 若业务上真没有“无值”语义,也要加一个占位的
Invalid = 0并文档说明 - 基础类型选
byte或short时更要小心:enum E : byte { A = 255 }后再写E.B就会溢出
需要多选组合时必须加 [Flags] 特性
没加 [Flags] 的枚举调用 .ToString() 或传给调试器时,只会显示数字或单个名称;加了之后才能正确解析位或结果:
[Flags]
public enum Permission { None = 0, Read = 1, Write = 2, Execute = 4 }
var p = Permission.Read | Permission.Write; // 值为 3
Console.WriteLine(p); // 输出 "Read, Write",而不是 "3"
- 必须用 2 的幂赋值(
1, 2, 4, 8...),或用左移(Read = 1 << 0)保证不重叠 -
HasFlag()性能较差,推荐用位与判断:(p & Permission.Read) == Permission.Read - JSON 序列化默认输出数字,要用
JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter())才转成字符串
给枚举加方法只能靠扩展类,不能写在 enum 里
C# 枚举本身不能定义方法、属性或构造函数,所有逻辑封装都得走 static class 扩展:
public enum Status { Pending, Running, Done }
public static class StatusExtensions {
public static bool IsTerminal(this Status s) => s == Status.Done;
public static string ToDisplayName(this Status s) => s switch {
Status.Pending => "等待中",
Status.Running => "运行中",
Status.Done => "已完成",
_ => "未知"
};
}
- 扩展方法名别跟内置方法冲突,比如别叫
ToString或GetValue - 如果要支持
null安全调用,扩展方法参数类型得是Status?,且开头加空值检查 - C# 14 的 extension 块语法虽新,但目前主流框架(.NET 6/8)还不完全支持,建议先用传统静态类
最常被忽略的是:枚举值在反序列化、数据库读取、API 接口传入时,几乎从不校验是否合法 —— Enum.IsDefined 得主动加,不能依赖编译器。


















