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

含枚举的抽象类无法正确序列化,如何用System.Text.Json解决?

解决System.Text.Json序列化卡牌Value字段为空对象的问题

问题出在Card类的Value字段声明为Enum基类型,System.Text.Json默认无法识别具体的枚举派生类型,导致序列化时仅输出空对象{},反序列化也无法正确还原枚举值。以下是仅使用System.Text.Json的解决方案:

方案1:自定义Enum基类转换器

通过实现JsonConverter<Enum>,在序列化时记录枚举的具体类型和值,反序列化时根据记录的类型还原枚举实例。

步骤1:创建自定义转换器

在Domain项目中添加如下转换器类:

using System.Text.Json;
using System.Text.Json.Serialization;

namespace Domain;

public class EnumBaseConverter : JsonConverter<Enum>
{
    public override Enum? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType != JsonTokenType.StartObject)
            throw new JsonException("枚举值序列化格式错误,应为对象类型");

        string? enumTypeFullName = null;
        string? enumValueStr = null;

        while (reader.Read())
        {
            if (reader.TokenType == JsonTokenType.EndObject)
                break;

            if (reader.TokenType != JsonTokenType.PropertyName)
                throw new JsonException("枚举值对象格式错误,应包含属性名");

            var propName = reader.GetString();
            reader.Read();

            switch (propName)
            {
                case "$type":
                    enumTypeFullName = reader.GetString();
                    break;
                case "value":
                    enumValueStr = reader.GetString();
                    break;
                default:
                    reader.Skip();
                    break;
            }
        }

        if (string.IsNullOrEmpty(enumTypeFullName) || string.IsNullOrEmpty(enumValueStr))
            throw new JsonException("枚举值缺少类型或值信息");

        var enumType = Type.GetType(enumTypeFullName);
        if (enumType == null || !enumType.IsEnum)
            throw new JsonException("无效的枚举类型");

        return Enum.Parse(enumType, enumValueStr) as Enum;
    }

    public override void Write(Utf8JsonWriter writer, Enum value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();
        writer.WriteString("$type", value.GetType().AssemblyQualifiedName);
        writer.WriteString("value", value.ToString());
        writer.WriteEndObject();
    }
}

步骤2:为Value字段添加转换器标记

修改Card类的Value字段,指定使用上述转换器:

[JsonDerivedType(typeof(BlackCard), typeDiscriminator: "blackCard")]
[JsonDerivedType(typeof(ColoredCard), typeDiscriminator: "coloredCard")]
public abstract class Card
{
    [JsonConverter(typeof(EnumBaseConverter))]
    public Enum Value { get; set; } = default!;
}

步骤3:验证序列化与反序列化

现在GameState实例序列化后,卡牌的Value字段会输出类似以下格式的内容:

{
  "$type": "Domain.EBlackCardValue, Domain",
  "value": "Wild"
}

反序列化时也能正确还原对应的枚举值。

方案2:调整Card类为泛型结构(可选)

如果允许修改现有类结构,可以将Card改为泛型类,让Value字段直接对应具体枚举类型,避免基类型序列化问题:

[JsonDerivedType(typeof(BlackCard), typeDiscriminator: "blackCard")]
[JsonDerivedType(typeof(ColoredCard), typeDiscriminator: "coloredCard")]
public abstract class Card<TEnum> where TEnum : Enum
{
    public TEnum Value { get; set; } = default!;
}

public class BlackCard : Card<EBlackCardValue>
{
    public BlackCard(EBlackCardValue value)
    {
        Value = value;
    }
}

public class ColoredCard : Card<EColoredCardValue>
{
    public ColoredCard(EColoredCardValue value)
    {
        Value = value;
    }
}

这种方式无需自定义转换器,System.Text.Json能直接正确序列化和反序列化枚举值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 03:05:28