最常用安全的枚举遍历方式是enum.getnames和enum.getvalues:前者返回string[],适合日志或下拉;后者返回array需cast转换,且不自动包含flags组合项。

怎么用 Enum.GetNames 和 Enum.GetValues 遍历枚举
遍历枚举最常用、最安全的方式就是这两个静态方法。它们返回的是字符串数组和对象数组,不依赖反射,性能好,也兼容 .NET Framework 和 .NET Core/5+。
注意:Enum.GetValues 返回的是 Array,不是泛型集合,需要显式转换类型;而 Enum.GetNames 直接返回 string[],适合做下拉选项或日志输出。
-
Enum.GetNames(typeof(Status))→["Pending", "Approved", "Rejected"] -
Enum.GetValues(typeof(Status))→Array,需转成Status[]才能 foreach - 如果枚举有 [Flags] 特性,
GetValues仍只返回基础值(不含组合项),别指望它自动列出Pending | Approved
foreach (string name in Enum.GetNames(typeof(Status)))
{
Console.WriteLine(name); // 输出名称
}
<p>foreach (Status value in Enum.GetValues(typeof(Status)).Cast<status>())
{
Console.WriteLine($"{value} = {(int)value}"); // 输出值和整数映射
}</status></p>
怎么把字符串安全转成枚举值(避免抛异常)
直接用 Enum.Parse 或 Enum.TryParse 是标准做法,但关键在「安全」——必须处理大小写、空格、无效输入这三类问题。
Enum.TryParse 默认区分大小写且不忽略空格,所以生产代码里几乎总要加 true(忽略大小写)和 Trim() 预处理。
-
Enum.TryParse("pending", out Status s)→false(默认区分大小写) -
Enum.TryParse("pending", true, out s)→true(第二个参数为true表示忽略大小写) - 若字符串含前后空格,务必先
.Trim(),否则TryParse会失败 - 不要用
Parse,除非你确定输入绝对可信;它遇到非法字符串直接抛ArgumentException
string input = " APPROVED ";
if (Enum.TryParse<status>(input.Trim(), true, out var result))
{
Console.WriteLine(result); // Approved
}
else
{
Console.WriteLine("无效状态");
}</status>
为什么 ToString() 有时输出数字而不是名称
这不是 bug,是枚举变量未被正确初始化或底层值不对应任何命名项时的默认行为。比如你手动赋了 (Status)999,再调 ToString() 就会输出 "999"。
常见诱因:反序列化 JSON 时用了 int 值但没校验范围;数据库查出的整数直接强转枚举;或者用了 [Flags] 但传入了未定义的位组合。
- 检查值是否在枚举定义范围内:
Enum.IsDefined(typeof(Status), value) - 若不确定,别直接
ToString(),先用IsDefined判断,再决定显示名称还是原始数字 - JSON 序列化时,用
JsonStringEnumConverter(System.Text.Json)或StringEnumConverter(Newtonsoft)可强制按名称序列化,避免数字泄露
自定义枚举描述(DescriptionAttribute)怎么取
想让枚举项带中文说明或额外元数据?得靠 System.ComponentModel.DescriptionAttribute,但 C# 没内置快捷方法读取,必须手写反射逻辑。
重点:每次调用都要走反射,别在高频路径(如循环内、HTTP 请求处理中)反复调;建议提前缓存到 Dictionary<enum string></enum>。
- 给枚举成员加
[Description("待审核")],不是给整个枚举类型加 - 获取描述时,用
member.GetCustomAttribute<descriptionattribute>()?.Description</descriptionattribute> - 如果没加
DescriptionAttribute,返回null,记得判空,别直接.ToString() - 别和
DisplayNameAttribute混用——后者主要用于 UI 绑定,语义不同
var field = typeof(Status).GetField("Pending");
var desc = field?.GetCustomAttribute<descriptionattribute>()?.Description ?? "无描述";</descriptionattribute>
枚举看似简单,但字符串往返转换、未定义值处理、描述读取这些环节,稍不注意就会在边界 case 上掉坑里。尤其在对接前端或外部系统时,输入不可控,TryParse 的大小写参数和 IsDefined 校验几乎不能省。











