将 JSON 字符串反序列化为具有抽象类型的对象

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

我正在尝试将复杂的嵌套 json 反序列化为我的对象。 唯一的事情是,在我的对象中,我使用抽象类型,因此它必须具有一些逻辑才能使用正确的派生类。

类型保存在枚举中。

为了解释它,我将保持它相当简单,我们只嵌套一次,但出于我的目的,它更多地嵌套对象和类型。

json

{
   "screen":{
      "type":"Component",
      "footer":{
         "type":"Bar"
      },
      "header":{
         "type":"Top"
      }
   }
}

课程

public abstract class Screen
{
    public abstract ScreenType Type { get; }
}

public enum ScreenType
{
    Component,
    b,
    c,
    d,
    e
}

public sealed class ComponentScreen : Screen
{
    public override ScreenType Type => ScreenType.Component;
    public Header? Header { get; init; }
    public Footer? Footer { get; init; }
    public bool? ShowStuff {get; init; }

}

public abstract class Header : ITyped<HeaderType>
{
    public abstract HeaderType Type { get; }
}

public enum HeaderType
{
    Top,
    b,
    c,
    d
}

public sealed class TopScreenHeader : Header
{
    public override HeaderType Type => HeaderType.Top;
    public string MyStuff { get; }
}

不可能只更改所有抽象类型或编写转换器,因为有多个抽象类型具有 X 个派生对象。 JSON 也不一致。

我当前使用newtonsoft的代码

var screen = JsonConvert.DeserializeObject<Screen>(jsonString, new JsonSerializerSettings {
    TypeNameHandling = TypeNameHandling.Objects,
    ContractResolver = new CamelCasePropertyNamesContractResolver()

}

这不起作用并给出错误:

Could not create an instance of type Screens.Screen. Type is an interace or abstract class and cannot be instantiated. Path 'screen', line 1, position 10.
c# json serialization
1个回答
0
投票

自 .NET 7 起,您可以使用

System.Text.Json
处理 类型层次结构:

[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")]
[JsonDerivedType(typeof(ComponentScreen),"Component")]
// all other Screen types ...
public abstract class Screen
{
    public abstract ScreenType Type { get; }
}

[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")]
[JsonDerivedType(typeof(TopScreenHeader), "Top")]
// all other Header types ...
public abstract class Header : ITyped<HeaderType>
{
    public abstract HeaderType Type { get; }
}

请注意,您的 json 并不代表屏幕,而是代表某些屏幕支架类型:

class ScreenHolder
{
    public Screen Screen { get; set; }
}

及用法:

var js = """
{
   "screen":{
      "type":"Component",
      "footer":{
         "type":"Bar"
      },
      "header":{
         "type":"Top"
      }
   }
}
""";

var deserialize = JsonSerializer.Deserialize<ScreenHolder>(js, new JsonSerializerOptions{PropertyNameCaseInsensitive = true});
© www.soinside.com 2019 - 2024. All rights reserved.