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

System.Text.Json中如何为特定枚举字段回退默认转换器输出数值

特定枚举字段按底层数字类型序列化的实现方法

完全可以实现,无需修改字段的枚举类型,也不需要调整全局JSON序列化配置。System.Text.Json 对属性/字段显式标注的转换器有最高优先级,会覆盖全局配置的转换器规则。

实现步骤

  1. 编写通用的枚举转数字序列化转换器
    这个转换器为全局适配,不需要为单个枚举重复编写逻辑,同时兼容普通枚举、可空枚举类型:
using System.Text.Json;
using System.Text.Json.Serialization;

public class EnumToNumberJsonConverter : JsonConverterFactory
{
    public override bool CanConvert(Type typeToConvert)
    {
        // 匹配所有枚举类型(含可空枚举)
        return typeToConvert.IsEnum || 
               (Nullable.GetUnderlyingType(typeToConvert)?.IsEnum == true);
    }

    public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
    {
        // 拆解可空枚举的实际类型
        var enumType = Nullable.GetUnderlyingType(typeToConvert) ?? typeToConvert;
        // 实例化泛型内部转换器
        var innerConverterType = typeof(InnerEnumNumberConverter<>).MakeGenericType(enumType);
        return (JsonConverter)Activator.CreateInstance(innerConverterType);
    }

    // 内部核心序列化逻辑
    private class InnerEnumNumberConverter<TEnum> : JsonConverter<TEnum> where TEnum : struct, Enum
    {
        public override TEnum Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            // 从JSON数字值反序列化为枚举
            if (reader.TokenType == JsonTokenType.Number)
            {
                var numericVal = reader.GetInt64();
                return (TEnum)Enum.ToObject(typeof(TEnum), numericVal);
            }
            // 兼容字符串格式的数字值,避免反序列化报错
            if (reader.TokenType == JsonTokenType.String && long.TryParse(reader.GetString(), out var strNumVal))
            {
                return (TEnum)Enum.ToObject(typeof(TEnum), strNumVal);
            }
            throw new JsonException($"无法将当前值转换为枚举 {typeof(TEnum).Name}");
        }

        public override void Write(Utf8JsonWriter writer, TEnum value, JsonSerializerOptions options)
        {
            // 序列化时直接输出枚举的底层数值,不做字符串转换
            writer.WriteNumberValue(Convert.ToInt64(value));
        }
    }
}
  1. 在指定字段上应用转换器特性
    只需要给需要按数字输出的枚举字段标注[JsonConverter]特性,其他字段不受任何影响,仍走全局的字符串枚举转换规则:
// 原有枚举定义保持不变
public enum OperationType : byte
{
    Create = 0,
    Update = 1,
    Delete = 2
}

public class OperationLog
{
    public string LogContent { get; set; }

    // 该字段单独按底层byte类型输出JSON数字
    [JsonConverter(typeof(EnumToNumberJsonConverter))]
    public OperationType OpType { get; set; }

    // 其余枚举字段正常走全局字符串转换规则,比如序列化为"Create"/"Update"
    public OperationType OriginOpType { get; set; }
}

核心规则说明

System.Text.Json 的转换器优先级规则:属性/字段上通过[JsonConverter]显式指定的转换器 > 全局配置中注册的转换器 > 框架内置默认转换器。
因此即使全局已经启用了JsonStringEnumConverter,标注了自定义数字转换器的字段也会完全绕开全局字符串转换逻辑,按数字类型输出,完全符合约束要求。

注意事项

  • 全程不需要修改枚举本身定义,也不需要把字段类型改成byte/int,完全保留原有的强类型枚举属性
  • 转换器自动支持可空枚举类型(比如OperationType?),不需要额外适配
  • 不会对全局配置、其他无特性标注的字段产生任何副作用

内容的提问来源于stack exchange,提问作者user1649304

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.24 01:45:03