You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 14:06:30