C# 反序列化具有混合值System.Text.JSON的JSON数组

C# 反序列化具有混合值System.Text.JSON的JSON数组,c#,json,inheritance,system.text.json,C#,Json,Inheritance,System.text.json,我正在尝试创建一个在.NETCore3.1中呈现的页面,它呈现基于JSON的页面 在这篇文章的结尾,我怎样才能真正地对JSON进行序列化呢 我尝试过反序列化它,但是它不起作用,因为我丢失了每个组件的数据, 因为Page类有一个列表——但我需要它是一个不同组件的列表 页面模型: public class Page { public int id { get; set; } public string pagename { get; set; }

我正在尝试创建一个在.NETCore3.1中呈现的页面,它呈现基于JSON的页面

在这篇文章的结尾,我怎样才能真正地对JSON进行序列化呢

我尝试过反序列化它,但是它不起作用,因为我丢失了每个组件的数据, 因为Page类有一个
列表
——但我需要它是一个不同组件的列表

页面模型:

public class Page
    {
        public int id { get; set; }
        public string pagename { get; set; }
        public string metatitle { get; set; }
        public string metadescription { get; set; }
        public string created_at { get; set; }
        public string updated_at { get; set; }
        public List<Component> components { get; set; }
    }

    public class Pages
    {
        public List<Page> pages { get; set; }
    }
一个组成部分:

public class Title : Component
    {
        public string component { get; set; }
        public int id { get; set; {
        public string titletext { get; set; }
    }
这是JSON:

{
      "id":1,
      "pagename":"home",
      "metatitle":"no title",
      "metadescription":"no meta",
      "created_at":"2020-05-31T16:35:52.084Z",
      "updated_at":"2020-05-31T16:35:52.084Z",
      "components":[
         {
            "component":"components.titletext",
            "id":1,
            "titletext":"hello"
         },
         {
            "component":"components.section",
            "id":2,
            "titletext":"hello",
            "descriptiontext":"its a beatiful day in lost santos",
            "buttonlink":"/go"
         },
         {
            "component":"components.cta",
            "id":3,
            "sectiontitle":"hello",
            "buttonlink":"/go",
            "buttontext":"click me"
         }
      ]
   }

如果不希望像这样将所有属性添加到
组件
类:

public class Component
{
    public string component { get; set; }
    public int id { get; set; }
    public string titletext { get; set; }
    public string sectiontitle { get; set; }
    public string buttonlink { get; set; }
    public string descriptiontext { get; set; }
}
例如,您需要编写自定义代码(不是很好的实现,但可以使用json,您不需要手动解析每个字段):

公共类ComponentConverter:JsonConverter
{
公共覆盖组件读取(参考Utf8JsonReader reader,类型为typeToConvert,JsonSerializerOptions选项)
{
使用(var doc=JsonDocument.ParseValue(ref reader))
{
var type=doc.RootElement.GetProperty(@“组件”).GetString();
开关(类型)
{
案例“components.titletext”:
返回JsonSerializer.Deserialize(doc.RootElement.GetRawText());
//其他类型处理
默认值:返回JsonSerializer.Deserialize(doc.RootElement.GetRawText());
}
}
}
公共重写无效写入(Utf8JsonWriter编写器、组件值、JsonSerializerOptions选项)
{
抛出新的NotImplementedException();
}
}
公共类组件
{
公共字符串组件{get;set;}
公共int id{get;set;}
}
公共类标题:组件
{
公共字符串titletext{get;set;}
}
和使用示例:

var json = @"[
     {
        ""component"":""components.titletext"",
        ""id"":1,
        ""titletext"":""hello""
     },
     {
""component"":""components.section"",
        ""id"":2,
        ""titletext"":""hello"",
        ""descriptiontext"":""its a beatiful day in lost santos"",
        ""buttonlink"":""/go""
     },
     {
""component"":""components.cta"",
        ""id"":3,
        ""sectiontitle"":""hello"",
        ""buttonlink"":""/go"",
        ""buttontext"":""click me""
     }
  ]";
var deserializeOptions = new JsonSerializerOptions();
deserializeOptions.Converters.Add(new ComponentConverter());
JsonSerializer.Deserialize<List<Component>>(json, deserializeOptions).Dump();
var json=@”[
{
“组件”:“组件.标题文本”,
“id”:1,
“标题文字”:“您好”
},
{
“”组件“”:“”组件。节“”,
“id”:2,
“titletext”:“你好”,
“这是在迷失的桑托斯度过的美好的一天”,
“按钮链接”:“/go”
},
{
“组件”:“组件.cta”,
“id”:3,
“sectiontitle”:“你好”,
“按钮链接”:“/go”,
“按钮文本”:“单击我”
}
]";
var deserializeOptions=新的JsonSerializerOptions();
反序列化options.Converters.Add(newcomponentconverter());
反序列化(json,反序列化选项).Dump();

也不要将此转换器用作
JSONConverterateAttribute
的参数,因为它将以stackoverflow结束。

如果您想要/需要完全独立的无关类,可以使用不使用转换器的技术:

var ays = new List<A>();
var bees = new List<B>();

using var doc = JsonDocument.Parse(json);
foreach (var block in doc.RootElement.EnumerateArray())
{
    switch (block.GetProperty("component").GetString())
    {
        case "typeA": ays.Add(Deserialise<A>(block)); break;
        case "typeB": bees.Add(Deserialise<B>(block)); break;
        // ... case 
        //default: ...
    }
}

var composite = new
{
    As = ays,
    Bs = bees 
};

// This is OK, but if you need to speed it up, please have a look at
// https://stackoverflow.com/questions/58138793/system-text-json-jsonelement-toobject-workaround
static T Deserialise<T>(JsonElement e) => JsonSerializer.Deserialize<T>(e.GetRawText(), options: new JsonSerializerOptions { PropertyNameCaseInsensitive = true });

var=newlist();
var=newlist();
使用var doc=JsonDocument.Parse(json);
foreach(doc.RootElement.EnumerateArray()中的变量块)
{
开关(block.GetProperty(“组件”).GetString()
{
案例“typeA”:ays.Add(反序列化(块));break;
案例“typeB”:bees.Add(反序列化(块));break;
//…案例
//默认值:。。。
}
}
var复合=新
{
As=ays,
Bs=蜜蜂
};
//这是可以的,但是如果你需要加速,请看
// https://stackoverflow.com/questions/58138793/system-text-json-jsonelement-toobject-workaround
静态T反序列化(JsonElement e)=>JsonSerializer.Deserialize(e.GetRawText(),选项:新的JsonSerializerOptions{PropertyNameCaseSensitive=true});

一种方法是,创建一个自定义反序列化类(检查)编辑->粘贴特殊->粘贴JSON为类这行
“descriptiontext”中缺少一个逗号:“这是lost santos的美好一天”
,因为这两个类之间唯一的区别是
Title
具有比
组件
更多的属性,您可以反序列化到
列表
。但是,如果需要多态层次结构,则需要编写一个自定义的
JsonConverter
。看看,这正是我所希望的。您提到此解决方案“性能不高”,能否为我指出一个方向或给我一个如何使其性能更高的线索?@user2839999很乐意提供帮助!至于性能,我没有很多现成的想法,至少如果它们不涉及手动处理所有字段的话。也许会给你一些想法。另外,请检查此实现的性能是否对您来说是一个值得关注的问题,因为有时“足够好”真的足够好=)
var json = @"[
     {
        ""component"":""components.titletext"",
        ""id"":1,
        ""titletext"":""hello""
     },
     {
""component"":""components.section"",
        ""id"":2,
        ""titletext"":""hello"",
        ""descriptiontext"":""its a beatiful day in lost santos"",
        ""buttonlink"":""/go""
     },
     {
""component"":""components.cta"",
        ""id"":3,
        ""sectiontitle"":""hello"",
        ""buttonlink"":""/go"",
        ""buttontext"":""click me""
     }
  ]";
var deserializeOptions = new JsonSerializerOptions();
deserializeOptions.Converters.Add(new ComponentConverter());
JsonSerializer.Deserialize<List<Component>>(json, deserializeOptions).Dump();
var ays = new List<A>();
var bees = new List<B>();

using var doc = JsonDocument.Parse(json);
foreach (var block in doc.RootElement.EnumerateArray())
{
    switch (block.GetProperty("component").GetString())
    {
        case "typeA": ays.Add(Deserialise<A>(block)); break;
        case "typeB": bees.Add(Deserialise<B>(block)); break;
        // ... case 
        //default: ...
    }
}

var composite = new
{
    As = ays,
    Bs = bees 
};

// This is OK, but if you need to speed it up, please have a look at
// https://stackoverflow.com/questions/58138793/system-text-json-jsonelement-toobject-workaround
static T Deserialise<T>(JsonElement e) => JsonSerializer.Deserialize<T>(e.GetRawText(), options: new JsonSerializerOptions { PropertyNameCaseInsensitive = true });