C#使用Macross.Json.Extensions序列化枚举带双引号如何解决
问题场景
使用Macross.Json.Extensions库时,对标注了JsonStringEnumMemberConverter的Interval枚举执行序列化,预期输出无包裹的纯数字结果(如FifteenMinute枚举值输出15),实际得到带转义双引号的字符串\"15\",不符合预期。
相关代码如下:
序列化逻辑:
public void Test(Interval interval) { var asd = JsonSerializer.Serialize(interval, new JsonSerializerOptions { NumberHandling = JsonNumberHandling.AllowReadingFromString }); // 实际结果: \"15\",预期结果: 15 var intervalMinutes = int.Parse(interval.ToString()); }
枚举定义:
[JsonConverter(typeof(JsonStringEnumMemberConverter))] public enum Interval { [EnumMember(Value = "1")] OneMinute, [EnumMember(Value = "5")] FiveMinute, [EnumMember(Value = "15")] FifteenMinute, [EnumMember(Value = "30")] ThirtyMinute, [EnumMember(Value = "60")] OneHour, [EnumMember(Value = "240")] FourHour, [EnumMember(Value = "1440")] OneDay, [EnumMember(Value = "10080")] OneWeek, [EnumMember(Value = "21600")] FifteenDays }
问题原因
输出带双引号的核心原因是JsonStringEnumMemberConverter本身就是为字符串序列化设计的转换器,只要使用它,无论枚举的映射值是不是数字格式,序列化结果都会是包裹双引号的JSON字符串类型。
配置的JsonNumberHandling.AllowReadingFromString仅在反序列化时生效,作用是允许从字符串内容解析数字,完全不影响枚举序列化的输出格式。
修复方案
根据实际需求二选一即可:
- 自定义数值型枚举转换器(推荐,完全匹配预期)
实现自定义JsonConverter<Interval>,序列化时读取EnumMember配置的Value值,直接以数字类型写入JSON,不做字符串包装,同时兼容数字/字符串格式的反序列化读取:
将枚举上的原转换器替换为自定义转换器即可,原有枚举定义无需修改:using System.Reflection; using System.Runtime.Serialization; using System.Text.Json; using System.Text.Json.Serialization; public class IntervalNumericConverter : JsonConverter<Interval> { public override Interval Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { string valueStr = reader.TokenType switch { JsonTokenType.Number => reader.GetInt32().ToString(), JsonTokenType.String => reader.GetString() ?? throw new JsonException("Interval值不能为空"), _ => throw new JsonException($"不支持的Token类型{reader.TokenType}") }; foreach (FieldInfo field in typeof(Interval).GetFields(BindingFlags.Public | BindingFlags.Static)) { if (field.GetCustomAttribute<EnumMemberAttribute>() is { Value: string enumValue } && enumValue == valueStr) { return (Interval)field.GetValue(null)!; } } throw new JsonException($"不存在值为{valueStr}的Interval枚举项"); } public override void Write(Utf8JsonWriter writer, Interval value, JsonSerializerOptions options) { FieldInfo field = value.GetType().GetField(value.ToString())!; if (field.GetCustomAttribute<EnumMemberAttribute>() is { Value: string enumValue }) { writer.WriteNumberValue(int.Parse(enumValue)); return; } // 未配置EnumMember时兜底输出枚举底层整型值 writer.WriteNumberValue((int)value); } }[JsonConverter(typeof(IntervalNumericConverter))] public enum Interval { // 原有枚举项保持不变 } - 移除原字符串枚举转换器(仅适用于不需要自定义枚举映射值的场景)
直接删掉枚举上的[JsonConverter(typeof(JsonStringEnumMemberConverter))]特性,此时System.Text.Json会默认按枚举底层整型值序列化,但输出的是枚举定义的顺序值(OneMinute输出0、FiveMinute输出1),不会读取EnumMember配置的1、5、15,不符合当前输出要求,非必要不选。
内容的提问来源于stack exchange,提问作者nop
相关产品推荐
相关产品推荐

