GetCustomAttribute读取枚举项的DescriptionAttribute需手动为每个枚举值添加[Description("xxx")]特性,反射获取时必须针对字段而非类型,未添加则返回null,不可fallback到字段名;推荐封装扩展方法并缓存结果。

用 GetCustomAttribute 读取枚举项的 DescriptionAttribute
直接上核心:C# 枚举本身不带描述信息,必须手动给每个值加 [Description("xxx")],再用反射读取。没加这个特性,GetCustomAttribute 就返回 null,不会 fallback 到字段名。
常见错误是以为加了注释或 XML doc 就能读到——不行,只有 DescriptionAttribute 才被标准方式识别。
-
Enum.GetNames(typeof(MyEnum))只返回字段名字符串,不涉及任何自定义属性 - 必须对每个枚举值(而非类型)调用
GetCustomAttribute<DescriptionAttribute>() - 推荐封装成扩展方法,避免每次重复写反射逻辑
public static string GetDescription(this Enum value)
{
var field = value.GetType().GetField(value.ToString());
var attr = field?.GetCustomAttribute<DescriptionAttribute>();
return attr?.Description ?? value.ToString();
}为什么不能用 ToString() 或 GetName() 获取描述
ToString() 默认输出字段名;Enum.GetName() 也是字段名。它们完全不检查任何特性,性能虽好但和描述无关。
容易踩的坑:有人误以为 value.ToString("G") 或 "F" 格式能触发描述读取——不会,这些只是格式化输出规则,和元数据无关。
- 字段名含空格或特殊符号时,
ToString()会原样输出,但Description可以写成自然语言 - 同一个枚举值可能有多个别名场景(比如 "Active" 和 "启用中"),靠
Description更灵活 - 若字段名是缩写(如
Pending),而 UI 需要显示 "等待审批",就必须依赖Description
处理 null、空字符串和未定义 Description 的安全读取
实际项目里,不是每个枚举值都加了 Description,有些加了但值为空字符串,还可能遇到反射失败(比如动态生成的枚举)。硬解包会抛异常或返回意外结果。
- 务必判空
attr,再取attr.Description,否则 NRE - 建议默认 fallback 到
value.ToString(),而不是抛异常或返回null - 如果业务要求“必须有描述”,那就单独校验,不要混在通用读取逻辑里
- 注意:
DescriptionAttribute构造函数接受空字符串,所以attr.Description == ""是合法且可能有意为之
性能影响和缓存建议
反射读取 DescriptionAttribute 每次都会走元数据查找,高频调用(如表格渲染千条枚举数据)会有明显开销。
- 不要在循环里反复调用
GetField()+GetCustomAttribute() - 推荐静态只读字典缓存:键为
Enum值,值为描述字符串,首次访问时初始化 - 注意泛型约束:
where TEnum : Enum在 .NET 5+ 才支持,旧版本需用where TEnum : struct, IConvertible加运行时类型检查 - 缓存 key 用
Convert.ToInt64(value)而非value.GetHashCode(),避免底层表示变化导致错乱
最常被忽略的是缓存粒度——按枚举类型缓存比按单个值缓存更合理,毕竟一个枚举所有值的描述基本固定,没必要每个值单独查一次反射。


















