导读:本期聚焦于森沢创作的《C#怎么操作枚举类型?遍历枚举与字符串互转的实用语法详解》,敬请观看详情。在C#项目里把状态值存成枚举后,常遇到界面要显示中文、配置要读写字符串的问题。如果直接用ToString可能拿到字段名而非描述,Parse又容易因大小写或空格抛异常。本文从底层原理讲清枚举在IL层只是整数常量,随后给出GetValues遍历、Enum.GetName映射、TryParse安全转换等写法,并对比Attribute扩展描述信息的方案,帮你在业务代码里少写判断、少出bug。

在C#中,枚举(enum)本质上是一种值类型,编译后对应一个继承于System.Enum的整数常量集合。开发者习惯用枚举来表达有限的状态、类型或选项,因为它比裸int更具可读性,也能借助编译器做类型检查。不过真到了要展示、存储或反序列化的时候,往往要把枚举和字符串来回倒腾,这里头的语法细节和坑位值得拆开讲透。

C#怎么操作枚举类型?遍历枚举与字符串互转的实用语法详解

枚举的基础定义与底层存储

定义一个枚举时,如果不显式指定基础类型,默认底层是System.Int32。每个成员其实就是一个命名的常量,在中间语言(IL)层面被标记为字段并附上字面量值。理解这一点很关键,因为后面所有字符串转换,本质上都是在“整数值”“成员名”“附加描述”三者之间建立映射,而不是什么神秘反射操作。

比如下面这段定义,我们给日志级别做了显式赋值。显式赋值能避免新增成员时默认值漂移,也方便和数据库里的tinyint直接对齐。注意枚举成员本身不能包含空格,如果要在界面显示“Information”以外的文字,就得靠特性或字典来补充。

public enum LogLevel : byte
{
    Trace = 0,
    Debug = 1,
    Information = 2,
    Warning = 3,
    Error = 4,
    Critical = 5
}

从内存角度看,一个LogLevel变量只占一个字节,却享有编译期类型安全。当你写LogLevel level = LogLevel.Error;时,赋值器直接把4写进栈上变量。这种轻量特性让枚举非常适合做标志位(配合Flags特性)或作为Dictionary的键。但也正因为它太像整数,很多新手会直接把用户输入的string丢给转换方法,从而引入异常风险。

遍历枚举成员的几种写法

想要列出枚举里所有候选值,最常用的是Enum.GetValues。它返回一个Array,里面按定义顺序装着每个枚举实例。在泛型时代,我们可以用Enum.GetValues<TEnum>()(.NET Core 2.0+)拿到强类型数组,避免后面频繁拆箱。遍历本身不触及任何IO,纯CPU计算,性能可以放心用在下拉框绑定等场景。

下面示例演示如何把上面定义的LogLevel所有成员名和值打印出来。注意GetValues拿到的元素类型是object,需要转回具体枚举才能调用扩展方法。如果枚举带Flags,遍历出的依然是单个位定义,不会自动展开组合值。

foreach (LogLevel level in Enum.GetValues<LogLevel>())
{
    Console.WriteLine($"Name={level}, Value={(byte)level}");
}

// 旧版写法,仍广泛存在于存量代码
foreach (var item in Enum.GetValues(typeof(LogLevel)))
{
    LogLevel lv = (LogLevel)item;
    Console.WriteLine(lv);
}

除了GetValues,还可以用Enum.GetNames只拿字符串数组,或者借助反射拿FieldInfo来读取贴在成员上的特性。如果只是做下拉项,GetValues配合ToString最直观;如果要同时取描述,就得走反射缓存,否则高频调用会有明显开销。实际项目里建议把“枚举+描述”的映射在启动时扫一遍存进静态字典,后面直接查表。

枚举与字符串的相互转换

把枚举变成字符串最简单就是ToString,但它只给成员名。若要反过来,Enum.ParseEnum.TryParse是标准手段。二者区别在于:前者转换失败直接抛ArgumentException,后者返回bool且不抛异常,更适合处理外部输入。忽略大小写时传true给ignoreCase参数,能省掉自己ToLower的麻烦。

以下代码展示安全转换的典型写法。我们故意用一个不在枚举里的文本去试,TryParse会回退到默认值而不是崩溃。顺带一提,如果字符串其实是数字(如"4"),TryParse也能转成对应的Error,这点比很多人以为的更宽松,但也更容易掩盖脏数据,需要按业务决定是否禁止数字串。

string input = "warning";
if (Enum.TryParse<LogLevel>(input, true, out LogLevel result))
{
    Console.WriteLine($"解析成功:{result}");
}
else
{
    Console.WriteLine("解析失败,使用默认 Trace");
    result = LogLevel.Trace;
}

// 反向:枚举到字符串
string name = LogLevel.Critical.ToString(); // "Critical"

当界面要显示“错误信息”而非“Error”时,单纯ToString就不够了。可以给成员加DescriptionAttribute,再用反射读取。下面示例给出一个通用扩展方法,优先取描述,没有就退回成员名。这样既能保持代码里用英文枚举,又能让终端用户看到本地化文案,还不用每处都写switch。

using System.ComponentModel;
using System.Reflection;

public static class EnumExtensions
{
    public static string GetDescription(this Enum value)
    {
        FieldInfo fi = value.GetType().GetField(value.ToString());
        DescriptionAttribute attr = fi?.GetCustomAttribute<DescriptionAttribute>();
        return attr?.Description ?? value.ToString();
    }
}

// 使用
LogLevel lv = LogLevel.Error;
Console.WriteLine(lv.GetDescription());

最后提醒一点,字符串转枚举时不要信任前端传来的任何文本。即便用了TryParse,也应校验结果是否落在合法区间内,尤其是带Flags的枚举,组合值可能超出单成员范围。把转换逻辑收口到一个工具类里,配合单元测试覆盖大小写、空格、越界和数字串,才能让C#枚举在字符串世界里既灵活又稳当。

C#enumstring_conversion修改时间:2026-08-18 19:28:33

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。