C#枚举需谨慎选择底层类型和显式赋值:默认int,但可选byte/short/long以适配内存、互操作或大数值场景;否则易致类型转换异常或序列化失败。

直接说结论:C# 中用 enum 关键字定义枚举,最简形式就是 enum 名称 { 值1, 值2 },但实际使用中必须注意底层类型、显式赋值、可空性和序列化行为——否则很容易在反序列化或跨平台通信时出错。
枚举的底层类型和显式赋值怎么选
默认情况下,enum 底层是 int,但你可以显式指定为 byte、short、long 等。这影响内存占用和互操作性(比如和 C/C++ 结构体对齐,或与数据库 tinyint 字段映射)。
常见错误现象:Invalid cast exception 出现在把 byte 枚举转成 int 时没加显式转换;或者用 JsonSerializer 序列化时,值超出 int 范围却没改底层类型。
- 需要节省空间或对接硬件协议?优先用
enum Status : byte { Off = 0, On = 1 } - 要表示 Unix 时间戳级别大数值?用
enum EventId : long { Created = 1L - 不显式赋值时,编译器从 0 开始自动递增;一旦某一项显式赋值(如
Running = 5),后续项仍按 +1 递推(Stopped = 6)
如何安全地解析字符串到枚举(避免 ArgumentException)
Enum.Parse 和 Enum.TryParse 是最常用方法,但默认区分大小写且不接受空格/连字符。生产环境里用户输入或 JSON 字段名往往不规范,硬用 Parse 容易崩。
使用场景:API 接收查询参数 ?state=ready-to-run,但枚举定义是 ReadyToRun。
- 用
Enum.TryParse—— 必须传(str, ignoreCase: true, out var result) ignoreCase: true,否则"readytorun"解析失败 - 若需支持连字符、下划线等风格,别依赖内置解析,先做字符串预处理:
str.Replace("-", "").Replace("_", "")再试 - 永远不用
Enum.Parse处理不可信输入;它抛ArgumentException或ArgumentNullException,而TryParse返回false更可控
Flags 枚举的位运算陷阱
带 [Flags] 特性的枚举不是“多个值随便加”,必须满足每个值都是 2 的幂(1, 2, 4, 8…),否则 .ToString()、HasFlag() 和 JSON 序列化都会出逻辑错误。
常见错误现象:MyFlags f = FlagA | FlagB; 输出 "FlagA, FlagB" 正常,但若 FlagB = 3(非 2 的幂),f.ToString() 可能返回空字符串或错误组合。
- 定义时强制用移位写法:
Read = 1 - 检查是否包含某标志,用位与:
(f & Read) == Read,而不是过时的f.HasFlag(Read)(性能差且在 .NET Core 6+ 已标记为 obsolete) - JSON 序列化时,默认输出数字;如需输出逗号分隔的名称列表,得配
JsonStringEnumConverter并启用AllowIntegerValues = false
枚举看着简单,但跨框架(.NET Framework/.NET 5+)、跨序列化器(System.Text.Json / Newtonsoft.Json)、跨语言(gRPC 的 proto enum 映射)时,底层类型不一致、命名策略不匹配、Flags 值非法这三类问题最容易被忽略——尤其在重构旧项目或对接遗留系统时。










