C#中Enum.ToString()返回非预期值的原因及解决方法
枚举多成员同值时ToString()返回异常的原因及解决办法
问题原因
在.NET中,枚举类型的实例本质上仅存储对应的整数值,不会记录它是通过哪个成员名称获取的。当多个枚举成员共享同一数值时,ToString()(以及Enum.GetName等名称解析方法)会返回枚举定义中第一个匹配该数值的成员名称(具体顺序取决于.NET对枚举元数据的遍历逻辑)。这就是为什么你调用country.UnitedKingdom.ToString()时返回其他成员名——因为所有这些成员的数值都是1,.NET无法区分你调用的是哪个成员,只能返回它找到的第一个匹配名称。
解决办法
由于你需要同时实现「调用对应成员时返回正确名称」和「字符串转枚举」的需求,推荐以下两种可行方案:
方案1:使用Description特性+扩展方法
给每个枚举成员添加DescriptionAttribute,通过扩展方法读取特性值实现精准的名称解析,同时支持字符串转枚举。
- 定义带特性的枚举:
using System.ComponentModel; public enum Country { [Description("UnitedKingdom")] UnitedKingdom = 1, [Description("Wales")] Wales = 1, [Description("England")] England = 1, [Description("Scotland")] Scotland = 1 }
- 编写枚举扩展方法:
using System; using System.ComponentModel; using System.Reflection; public static class EnumExtensions { // 获取枚举成员的自定义名称(优先取Description,无则返回成员名) public static string GetEnumName(this Enum enumValue) { FieldInfo fieldInfo = enumValue.GetType().GetField(enumValue.ToString()); DescriptionAttribute descAttr = fieldInfo?.GetCustomAttribute<DescriptionAttribute>(); return descAttr?.Description ?? enumValue.ToString(); } // 字符串转枚举,支持匹配成员名或Description public static T ParseToEnum<T>(string input) where T : Enum { foreach (FieldInfo field in typeof(T).GetFields(BindingFlags.Public | BindingFlags.Static)) { DescriptionAttribute descAttr = field.GetCustomAttribute<DescriptionAttribute>(); if (string.Equals(field.Name, input, StringComparison.OrdinalIgnoreCase) || string.Equals(descAttr?.Description, input, StringComparison.OrdinalIgnoreCase)) { return (T)field.GetValue(null); } } throw new ArgumentException($"无法将字符串\"{input}\"转换为枚举{typeof(T).Name}"); } }
- 使用示例:
// 获取正确名称 string ukName = Country.UnitedKingdom.GetEnumName(); // 返回"UnitedKingdom" string walesName = Country.Wales.GetEnumName(); // 返回"Wales" // 字符串转枚举 Country uk = EnumExtensions.ParseToEnum<Country>("UnitedKingdom"); Country scotland = EnumExtensions.ParseToEnum<Country>("Scotland");
方案2:使用字典映射(无需特性)
直接定义字典存储枚举成员与名称的映射,逻辑更直观,适合枚举成员较少的场景。
- 定义枚举(无需特性):
public enum Country { UnitedKingdom = 1, Wales = 1, England = 1, Scotland = 1 }
- 编写映射及扩展方法:
using System; using System.Collections.Generic; using System.Linq; public static class CountryExtensions { private static readonly Dictionary<Country, string> _countryToName = new Dictionary<Country, string> { { Country.UnitedKingdom, "UnitedKingdom" }, { Country.Wales, "Wales" }, { Country.England, "England" }, { Country.Scotland, "Scotland" } }; private static readonly Dictionary<string, Country> _nameToCountry = _countryToName.ToDictionary(kv => kv.Value, kv => kv.Key, StringComparer.OrdinalIgnoreCase); // 获取枚举成员对应名称 public static string GetName(this Country country) { return _countryToName.TryGetValue(country, out string name) ? name : country.ToString(); } // 字符串转枚举 public static Country Parse(string input) { return _nameToCountry.TryGetValue(input, out Country country) ? country : throw new ArgumentException($"无效的国家名称:{input}"); } }
- 使用示例:
string englandName = Country.England.GetName(); // 返回"England" Country wales = CountryExtensions.Parse("Wales");
内容的提问来源于stack exchange,提问作者Mr Fivian
相关产品推荐
相关产品推荐

