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

如何在System.Text.Json中实现带自定义回退的JsonStringEnumConverter

在System.Text.Json中实现未知枚举值自动回退到默认值

针对.NET 6中使用System.Text.Json处理外部API返回的JSON字符串,将未定义的枚举值自动反序列化为MyEnum.Unknown的需求,有两种简便可行的实现方案:

方案一:通用枚举转换器工厂(支持所有枚举类型)

这种方案适合需要处理多个枚举类型的场景,通过自定义JsonConverterFactory为每个枚举类型生成对应的转换器,统一处理未知值回退逻辑。

1. 泛型枚举转换器

首先定义一个泛型转换器,负责单个枚举类型的反序列化与序列化:

public class GenericEnumConverter<T> : JsonConverter<T> where T : struct, Enum
{
    private readonly T _defaultValue;

    public GenericEnumConverter(T defaultValue)
    {
        _defaultValue = defaultValue;
    }

    public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // 非字符串类型直接返回默认值
        if (reader.TokenType != JsonTokenType.String)
        {
            return _defaultValue;
        }

        var enumString = reader.GetString();
        // 尝试解析枚举,同时验证是否为已定义的枚举成员
        if (Enum.TryParse(enumString, ignoreCase: options.PropertyNameCaseInsensitive, out T result) 
            && Enum.IsDefined(typeof(T), result))
        {
            return result;
        }

        // 解析失败或值未定义时返回默认值
        return _defaultValue;
    }

    public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.ToString());
    }
}

2. 转换器工厂

实现JsonConverterFactory,用于判断类型是否为枚举,并创建对应的泛型转换器:

public class FallbackEnumConverterFactory : JsonConverterFactory
{
    private readonly object _defaultValue;

    public FallbackEnumConverterFactory(object defaultValue)
    {
        _defaultValue = defaultValue;
    }

    public override bool CanConvert(Type typeToConvert)
    {
        return typeToConvert.IsEnum;
    }

    public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
    {
        var converterType = typeof(GenericEnumConverter<>).MakeGenericType(typeToConvert);
        return (JsonConverter)Activator.CreateInstance(converterType, _defaultValue)!;
    }
}

3. 使用方式

在JsonSerializerOptions中注册该工厂,并指定回退的默认值:

var options = new JsonSerializerOptions
{
    Converters = { new FallbackEnumConverterFactory(MyEnum.Unknown) },
    PropertyNameCaseInsensitive = true // 根据API返回的大小写情况选择是否启用
};

// 反序列化示例
var json = "{\"EnumProperty\": \"UndefinedValue\"}";
var targetObject = JsonSerializer.Deserialize<YourModel>(json, options);
// targetObject.EnumProperty 会被设置为 MyEnum.Unknown

方案二:针对特定枚举的转换器(仅处理单个枚举)

如果只需要处理MyEnum这一个枚举类型,可以直接编写针对性的转换器,代码更简洁:

public class MyEnumConverter : JsonConverter<MyEnum>
{
    public override MyEnum Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType != JsonTokenType.String)
            return MyEnum.Unknown;

        var enumValue = reader.GetString();
        // 解析并验证是否为已定义的枚举成员
        if (Enum.TryParse(enumValue, ignoreCase: options.PropertyNameCaseInsensitive, out MyEnum result)
            && Enum.IsDefined(result))
        {
            return result;
        }

        return MyEnum.Unknown;
    }

    public override void Write(Utf8JsonWriter writer, MyEnum value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.ToString());
    }
}

使用方式

直接将转换器添加到JsonSerializerOptions中:

var options = new JsonSerializerOptions
{
    Converters = { new MyEnumConverter() },
    PropertyNameCaseInsensitive = true
};

关键注意点

  • Enum.TryParse默认允许解析未在枚举中定义的整数值对应的字符串(比如枚举未定义Value4,但字符串"4"会被解析为对应的整数值),因此必须配合Enum.IsDefined验证,确保只有已定义的枚举成员才会被返回。
  • 如果API返回的枚举值大小写与定义不一致,记得启用PropertyNameCaseInsensitive或在Enum.TryParse中手动设置ignoreCase: true。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 03:08:23