如何用System.Text.Json自定义枚举JSON转换器适配后端枚举?
问题分析与解决方案
你的思路方向是对的——用自定义JSON转换器来做枚举和后端字符串的适配,避免修改现有枚举和UI代码,但当前的转换器实现有问题:你继承了JsonConverter<string>,但实际要处理的是枚举类型,而不是string,所以Write方法的参数类型不对,没法直接关联到枚举的Description特性。
正确的实现步骤
- 调整转换器基类:应该继承
JsonConverter<T>(泛型,针对具体枚举)或者JsonConverter(非泛型,处理所有枚举),这样才能拿到枚举值来读取特性。 - 编写工具方法读取Description:通过反射获取枚举字段上的
DescriptionAttribute值。 - 实现序列化/反序列化逻辑:序列化时把枚举转成Description字符串,反序列化时把后端字符串转回对应的枚举值。
完整代码示例
1. 通用枚举Description转换器(支持所有枚举)
using System.ComponentModel; using System.Reflection; using System.Text.Json; using System.Text.Json.Serialization; public class EnumDescriptionConverter : JsonConverter<Enum> { // 获取枚举值的Description特性值 private string GetEnumDescription(Enum enumValue) { var fieldInfo = enumValue.GetType().GetField(enumValue.ToString()); var descriptionAttr = fieldInfo?.GetCustomAttribute<DescriptionAttribute>(); return descriptionAttr?.Description ?? enumValue.ToString(); } // 根据Description字符串找对应的枚举值 private TEnum GetEnumFromDescription<TEnum>(string description) where TEnum : Enum { foreach (var field in typeof(TEnum).GetFields()) { if (Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) is DescriptionAttribute attr && attr.Description == description) { return (TEnum)field.GetValue(null); } } // 找不到的话 fallback 到按名称解析,或者抛异常 return Enum.Parse<TEnum>(description); } public override Enum Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var description = reader.GetString(); return GetEnumFromDescription<Enum>(description); } public override void Write(Utf8JsonWriter writer, Enum value, JsonSerializerOptions options) { var description = GetEnumDescription(value); writer.WriteStringValue(description); } }
2. 针对特定枚举的转换器(如果只需要处理RenovationMode)
using System.Text.Json; using System.Text.Json.Serialization; public class RenovationModeConverter : JsonConverter<RenovationMode> { private string GetDescription(RenovationMode mode) { return mode switch { RenovationMode.RoofTruss => "Beams", RenovationMode.RoofTiles => "Slats", RenovationMode.CompleteRoofStructureReplacement => "RoofStructure", RenovationMode.Waterproofing => "Waterproofing", _ => mode.ToString() }; } private RenovationMode GetModeFromDescription(string description) { return description switch { "Beams" => RenovationMode.RoofTruss, "Slats" => RenovationMode.RoofTiles, "RoofStructure" => RenovationMode.CompleteRoofStructureReplacement, "Waterproofing" => RenovationMode.Waterproofing, _ => Enum.Parse<RenovationMode>(description) }; } public override RenovationMode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var description = reader.GetString(); return GetModeFromDescription(description); } public override void Write(Utf8JsonWriter writer, RenovationMode value, JsonSerializerOptions options) { var description = GetDescription(value); writer.WriteStringValue(description); } }
使用方式
在序列化时配置转换器:
var options = new JsonSerializerOptions(); // 通用转换器,支持所有枚举 options.Converters.Add(new EnumDescriptionConverter()); // 或者针对特定枚举的转换器 // options.Converters.Add(new RenovationModeConverter()); var mode = RenovationMode.RoofTruss; var json = JsonSerializer.Serialize(mode, options); // 输出结果:"Beams"
总结
你的核心思路是对的,但转换器的基类选错了,改成处理枚举类型的转换器后,就能通过反射或者switch读取Description特性,完成前后端的适配。
内容的提问来源于stack exchange,提问作者Wasyster
相关产品推荐
相关产品推荐

