为什么枚举序列化是每位 C# 开发者的痛点
\n\n您是否遇到过这样的情况:您精心编写的、处理枚举 (enum) 的 C# 代码,突然开始输出奇怪的数字,而不是清晰的名称?如果是这样,您并不孤单。Stack Overflow 上关于“JavaScriptSerializer - JSON serialization of enum as string”的问题已经积累了数千次浏览,这意味着很多人都遇到过这个问题。
\n\n让我们来弄清楚,为什么 JavaScriptSerializer 默认会将您漂亮的枚举名称变成无意义的数字,更重要的是,如何一劳永逸地解决这个问题。
\n\n问题:为什么枚举会变成数字?
\n\n默认情况下,JavaScriptSerializer(来自 System.Web.Script.Serialization 命名空间的类)会将枚举序列化为其整数值。这是因为每个枚举底层都是一个整数(默认为 int)。
public enum Status\n{\n Active = 1,\n Inactive = 2,\n Pending = 3\n}\n\npublic class Order\n{\n public int Id { get; set; }\n public Status OrderStatus { get; set; }\n}\n\n// 序列化\nvar order = new Order { Id = 1, OrderStatus = Status.Active };\nvar serializer = new JavaScriptSerializer();\nstring json = serializer.Serialize(order);\n// 结果: {"Id":1,"OrderStatus":1}\n\n\n您得承认,"OrderStatus":1 看起来信息量不足。想象一下,这样的 JSON 被发送到 API——客户端代码将不得不猜测数字 1 代表什么。
使用 JavaScriptSerializer 和枚举时的 5 大错误
\n\n错误 1:使用 EnumMemberAttribute 但未进行配置
\n\n许多开发者尝试使用来自 System.Runtime.Serialization 命名空间的 [EnumMember],认为这能解决问题。但 JavaScriptSerializer 默认不处理此属性。
[DataContract]\npublic enum Status\n{\n [EnumMember(Value = "active")]\n Active = 1,\n [EnumMember(Value = "inactive")]\n Inactive = 2\n}\n\n// JavaScriptSerializer 仍然会输出数字\n\n\n错误 2:忽略 ScriptIgnoreAttribute
\n\n有些人试图隐藏枚举属性,然后单独添加一个字符串表示。这会使代码复杂化并破坏数据完整性。
\n\n错误 3:通过 if/switch 手动转换
\n\n最常见的“权宜之计”是创建一个额外的字符串属性并进行手动转换:
\n\npublic class Order\n{\n public int Id { get; set; }\n public Status OrderStatus { get; set; }\n \n // 数据重复——不良实践\n public string OrderStatusString\n {\n get { return OrderStatus.ToString(); }\n }\n}\n\n\n问题:现在您有了两个需要同步的属性。迟早它们会不一致。
\n\n错误 4:忘记字符大小写
\n\n即使您解决了序列化问题,客户端代码可能期望 "active",但收到的却是 "Active"。大小写差异会导致 JavaScript 端的错误。
错误 5:使用过时的 JavaScriptSerializer 而非 Newtonsoft.Json
\n\n在现代 .NET 版本中,JavaScriptSerializer 类已被视为过时。Microsoft 建议使用 System.Text.Json 或 Newtonsoft.Json。但如果您在处理遗留项目或 Web Forms,则无法避免使用它。
如何正确地将枚举序列化为字符串:3 种可行的解决方案
\n\n解决方案 1:自定义转换器(推荐方法)
\n\n创建您自己的类,继承自 JavaScriptConverter,并将其注册到序列化器中。
public class EnumToStringConverter<T> : JavaScriptConverter where T : struct\n{\n public override IEnumerable<Type> SupportedTypes\n