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

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

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

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

public enum BlockType 
{
    T1,
    T2
}

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

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

[JsonPolymorphic(TypeDiscriminatorPropertyName = nameof(Type))]
[JsonDerivedType(typeof(Type1), 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
2个回答
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();
    }
}



0
投票

您的代码和属性中有一些错误。基本上反序列化无需自定义即可正常工作

JsonConverter

我可以建议您查看 2 个解决方案。

解决方案1:

请再次检查您的代码...

您尝试使用一种属性(类型)来检测实例类型和属性。 为此,您需要使用不同的 JSON 属性。

您可以将

JsonPolymorphic
属性更改为:

[JsonPolymorphic(TypeDiscriminatorPropertyName = "__type")]

在这种情况下,您的 JSON 字符串必须如下所示:

{
  "ListOfItems": [
    {
      "__type": "T1",
      "Type": "T1",
      "Value1": 10
    },
    {
      "__type": "T2",
      "Type": "T2",
      "Value2": 11
    }
  ]
}

在这种情况下,通过值“__type”反序列化器将创建类的正确实例,并将正确填充属性类型(到您的枚举值)。

解决方案2:

您可能想重新设计您的类继承。看来类

BaseType
一定是抽象的。在这种情况下,您可以覆盖继承类中的属性 Type。

请查看那里的代码片段:

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

public class Type1 : BaseType
{
    public override BlockType Type => BlockType.T1;
    required public int Value1 { get; set; }
}

public class Type2 : BaseType
{
    public override BlockType Type => BlockType.T2;
    required public int Value2 { get; set; }
}

在这种情况下,您的 JSON 字符串将与您提供的相同。

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