.NET 8..0 System.Text.JSON 反序列化 Json 多态不起作用

问题描述 投票:0回答:1

我在反序列化 Json 多态时遇到问题。这是一个最小的例子:

我有一个定义 JSON 类型的枚举:

public enum BlockType 
{
    T1,
    T2
}

基类和子类(以及容器):

public class Container
{
    required public List<BaseType> ListOfItems { get; set; }
}

[JsonPolymorphic(TypeDiscriminatorPropertyName = nameof(Type))]
[JsonDerivedType(typeof(Type2), nameof(BlockType.T1))]
[JsonDerivedType(typeof(Type2), nameof(BlockType.T2))]
public class BaseType
{
    [JsonConverter(typeof(JsonStringEnumConverter))]
    required public BlockType Type { get; set; }
}

public class Type1 : BaseType
{
    required public int Value1 { get; set; }
}

public class Type2 : BaseType
{
    required public int Value2 { get; set; }
}

我有一个输入 JSON:

var jsonBody = """
{
  "ListOfItems": [
    {
      "type": "T1",
      "Value1": 10
    },
    {
      "type": "T2",
      "Value2": 11
    }
  ]
}
""";

并调用序列化器:

var deserializeOptions = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true,
    WriteIndented = true,
};
var decoded = JsonSerializer.Deserialize<Container>(jsonBody, deserializeOptions);

序列化器不会返回任何错误。但是,当我检查返回的类型和列表

Container.ListOfItems
时,其中的每个项目都是
BaseType
,而不是派生的
Type1
Type2
。事实上,如果我投射该物体:

foreach (BaseType o in decoded.ListOfItems)
{
    if (o.Type == BlockType.T1)
    {
        Type1 obj = (Type1)o;
    }
}

我会得到一个

InvalidCastException: Cannot convert BaseType to Type1.

这个问题有解决办法吗?

c# .net .net-8.0 system.text.json
1个回答
0
投票

我个人已经放弃使用[JsonPolymorphic],而是编写了一个转换器。上述类的转换器看起来像这样

public class BaseTypeConverter : JsonConverter<BaseType> 
{
    public override BaseType? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        using var doc = JsonDocument.ParseValue(ref reader);
        var typestr = doc.RootElement.GetProperty("type").GetString()?.ToUpper();

        if (Enum.TryParse(typestr, out BlockType type)) {
            if (type == BlockType.T1) {
                return JsonSerializer.Deserialize<Type1>(doc.RootElement.GetRawText(), options);
            }
            else
            {
                return JsonSerializer.Deserialize<Type2>(doc.RootElement.GetRawText(), options);
            }
        }
    }

    public override void Write(Utf8JsonWriter writer, BaseType value, JsonSerializerOptions options)
    {
        // I'm only interested in deserializing
        throw new NotImplementedException();
    }
}


© www.soinside.com 2019 - 2024. All rights reserved.