我正在尝试将复杂的嵌套 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 也不一致。
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.
自 .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});