首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >如何反序列化包含C#中形状不同的对象的JSON数组?

如何反序列化包含C#中形状不同的对象的JSON数组?
EN

Stack Overflow用户
提问于 2021-03-23 15:21:58
回答 3查看 496关注 0票数 1

考虑以下JSON:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
  "Foo": "Whatever",
  "Bar": [
   { "Name": "Enrico", "Age": 33, "Country": "Italy" }, { "Type": "Video", "Year": 2004 },
   { "Name": "Sam", "Age": 18, "Country": "USA" }, { "Type": "Book", "Year": 1980 }
  ]
}

注意,Items数组是一个混合内容数组,它包含具有不同形状的对象。

这些形状之一可以使用以下类来描述:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Person 
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Country { get; set; }
}

相反,可以使用以下C#类来描述另一个形状:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Item 
{
    public string Type { get; set; }
    public int Year { get; set; }
}

我想通过使用C#或newtonsoft.json将这个JSON反序列化为一个System.Text.Json类。在这两种情况下,我都需要一个用于反序列化的类,但我不知道如何处理Bar数组。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class ClassToDeserialize
{
    public string Foo { get; set; }
    public List<what should I put here ???> Bar { get; set; }
}

如何反序列化这个JSON?

对于熟悉类型记录的人,我需要类似于union类型的东西(例如:将Bar属性定义为List<Person | Item>),但根据我的知识,C#中不支持联合类型。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2021-03-24 08:39:29

我将为列表项定义一个公共接口IBar,然后让类实现这个接口。IBar可能只是一个空接口,也可以选择将Type属性放入其中并向Person类添加一个合成Type属性以匹配:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface IBar
{
    string Type { get; }
}

class Person : IBar
{
    public string Type => "Person";
    public string Name { get; set; }
    public int Age { get; set; }
    public string Country { get; set; }
}

class Item : IBar
{
    public string Type { get; set; }
    public int Year { get; set; }
}

class ClassToDeserialize
{
    public string Foo { get; set; }
    public List<IBar> Bar { get; set; }
}

要从JSON填充类,可以使用以下简单的JsonConverter

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class BarConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(IBar).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);

        // If the "age" property is present in the JSON, it's a person, otherwise it's an item
        IBar bar;
        if (jo["age"] != null)
        {
            bar = new Person();
        }
        else
        {
            bar = new Item();
        }

        serializer.Populate(jo.CreateReader(), bar);

        return bar;
    }

    public override bool CanWrite => false;

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

最后一块拼图是用一个IBar属性装饰[JsonConverter]接口,告诉序列化程序在处理IBar时使用转换器。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[JsonConverter(typeof(BarConverter))]
interface IBar
{
    string Type { get; }
}

然后,您可以像通常那样反序列化:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var root = JsonConvert.DeserializeObject<ClassToDeserialize>(json);

下面是一个工作演示:https://dotnetfiddle.net/ENLgVx

票数 1
EN

Stack Overflow用户

发布于 2021-03-23 16:02:16

创建一个具有两个属性但具有可空选项的类。然后,可以使用各个类的属性创建两个接口。然后,一旦您收到它为一个列表,您可以组织成两个不同的列表类型IYourInterface

票数 3
EN

Stack Overflow用户

发布于 2021-03-23 16:56:52

这是可行的,但它比我预期的要复杂一些。首先创建一些接口:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface IPerson
{
    string Name { get; }
    int Age { get; }
    string Country { get; }
}

public interface IItem
{
    string Type { get; }
    int Year { get; }
}

}

我们会用它们来代表你的人和物品。

然后创建另一个类:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class JsonDynamicList
{
    private const string JsonData =
        @"{
            'Foo': 'Whatever',
            'Bar': [
                { 'Name': 'Enrico', 'Age': 33, 'Country': 'Italy' }, { 'Type': 'Video', 'Year': 2004 },
                { 'Name': 'Sam', 'Age': 18, 'Country': 'USA' }, { 'Type': 'Book', 'Year': 1980 }
                ]
        }";

    public string Foo { get; set; }
    public dynamic[] Bar { get; set; }
}

它与您创建的类相匹配,但我使用的是dynamic数组,而不是List<something>。还请注意,通过更改引号使您的JSON更加友好--它是同一个C#。

我们会继续增加那个班的成员。

首先,我创建了两个实现IPersonIItem的私有类。它们位于JsonDynamicList类中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private class PersonImpl :IPerson
{
    private readonly dynamic _person;
    public PersonImpl(dynamic person)
    {
        _person = person;
    }

    public IPerson AsPerson()
    {
        if (!IsPerson(_person))
        {
            return null;
        }
        //otherwise
        Name = _person.Name;
        Age = _person.Age;
        Country = _person.Country;
        return this;
    }

    public string Name { get; private set; } = default;
    public int Age { get; private set; } = default;
    public string Country { get; private set; } = default;
}

private class ItemImpl : IItem
{
    private readonly dynamic _item;
    public ItemImpl(dynamic item)
    {
        _item = item;
    }

    public IItem AsItem()
    {
        if (!IsItem(_item))
        {
            return null;
        }
        //otherwise
        Type = _item.Type;
        Year = _item.Year;
        return this;
    }

    public string Type { get; private set; } = default;
    public int Year { get; private set; } = default;
}

我使用了一些Newtonsoft魔术来实现JsonDynamicList的下两个成员。他们可以决定一个项目是IItem还是IPerson

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static bool IsPerson(dynamic person)
{
    var jObjectPerson = ((JObject) person).ToObject<Dictionary<string, object>>();
    return jObjectPerson?.ContainsKey("Age") ?? false;
}

public static bool IsItem(dynamic item)
{
    var jObjectItem = ((JObject)item).ToObject<Dictionary<string, object>>();
    return jObjectItem?.ContainsKey("Year") ?? false;
}

如果有人知道一个更好的方法来判断一个动态是否有一个特定的成员,我很想知道。

然后,我创建了一种方法来将数组中的一个项转换为输入项(嗯,它实际上不是一个强制转换,但您可以这样想)。我用了前两个,我想我要用第二个。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static IPerson AsPerson(dynamic person)
{
    var personImpl = new PersonImpl(person);
    return personImpl.AsPerson();
}

public static IItem AsItem(dynamic item)
{
    var itemImpl = new ItemImpl(item);
    return itemImpl.AsItem();
}

public IItem AsItem(int index)
{
    if (index < 0 || index >= Bar.Length)
    {
        throw new IndexOutOfRangeException();
    }
    return AsItem(Bar[index]);
}

public IPerson AsPerson(int index)
{
    if (index < 0 || index >= Bar.Length)
    {
        throw new IndexOutOfRangeException();
    }
    return AsPerson(Bar[index]);
}

一些便于测试的工作人员方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static string ItemToString(IItem item)
{
    return $"Type: {item.Type} - Year: {item.Year}";
}

public static string PersonToString(IPerson person)
{
    return $"Name: {person.Name} - Age: {person.Age} - Country: {person.Country}";
}

最后,一些测试代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var data = JsonConvert.DeserializeObject<JsonDynamicList>(JsonData);
Debug.WriteLine($"Foo: {data.Foo}");
foreach (dynamic obj in data.Bar)
{
    if (IsItem(obj))
    {
        string itemString = ItemToString(AsItem(obj));
        Debug.WriteLine(itemString);
    }
    else
    {
        string personString = PersonToString(AsPerson(obj));
        Debug.WriteLine(personString);
    }
}

这导致:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Foo: Whatever
Name: Enrico - Age: 33 - Country: Italy
Type: Video - Year: 2004
Name: Sam - Age: 18 - Country: USA
Type: Book - Year: 1980
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66772647

复制
相关文章
数据库-实验二
--1.简单查询 --a)查询供应商号码为S1的供应商的名称SNAME,所在城市CITY select SNAME,CITY from S where SNO='S1'; --b)查询颜色为红色的零件号码 select PNO from P where COLOR = '红'; --c)查询工程所在地为天津的工程名称JNAME select JNAME from J where CITY='天津'; --d)查询供应工程J1零件P1的供应商号码 select SNO from SPJ where J
手撕代码八百里
2020/07/28
5740
我的数据库实验报告册
实验二:基础数据如下 create database XSGL go use XSGL go create table student ( sno char(8) primary key, sname char(4) not null, ssex char(2) default ‘男’ check(ssex=’男’ or ssex=’女’), sage int, sdept char(10) not null ) create table course ( cno char(2)
苦咖啡
2018/05/07
7320
数据库表中常用的查询实验
select ename,sal from emp where deptno=10;
Twcat_tree
2022/11/30
1K0
新书连载:Oracle数据库的跟踪和分析方法
编辑说明:《Oracle性能优化与诊断案例精选》出版以来,收到很多读者的来信和评论,我们会通过连载的形式将书中内容公布出来,希望书中内容能够帮助到更多的读者朋友们。 在今天的技术领域,DevOps已经成为最热门的话题之一,DevOps是开发和运维一体化的实践趋势,也是运维掌握一定的开发能力,推动和协助开发进行适应高效运维的渐进变革。 在我的技术生涯中,对Oracle数据库的接触最多,感受也最深。如果说要将最值得推荐的技能展示给大家,那么我想推荐的就是Oracle跟踪方法。事实上,通过跟踪能够实现的也正是不
数据和云
2018/03/07
1.1K0
数据库课程设计实验报告–图书馆管理系统
声明:由于该项目已是四年前大一时所做,时隔已久,且本人已不从事java相关工作,恕不能解答各位问题!!! 无法提供数据库代码!!!
全栈程序员站长
2022/08/31
1.4K0
关系数据库的设计_关系型数据库的设计原则
1、设计一个合适的关系数据库系统的关键是关系数据库模式的设计,即应构造几个关系模式, 每个模式有哪些属性,怎样将这些相互关联的关系模式组建成一个适合的关系模型,关系数据库 的设计必须在关系数据库设计理论的指导下进行。 2、关系数据库设计理论有三个方面的内容:函数依赖、范式和模式设计。函数依赖起核心作用, 它是模式分解和模式设计的基础,范式是模式分解的标准。
全栈程序员站长
2022/09/23
2.3K0
关系数据库的设计_关系型数据库的设计原则
数据库模型设计——主键的设计
在数据库设计时,主要就是对实体和关系的设计,实体表现出来就是表,关系表现出来就是外键。而对于一个表,由两部分组成:主键和属性。主键的简单定义就是表中为每一行数据的唯一标识。其实更准确的说法,每一行数据的唯一标识是候选键(Candidate Key),一个表中可以有很多个候选键,主键是候选键中的一个,主要用于更方便的检索和管理数据。一个表中可以有多个候选键,但是只有一个主键。由于主键常常用于检索数据,也用于表之间的关联,所以主键的设计的好坏将会严重影响数据操作的性能。下面来介绍下主键设计的几个考虑因素。
深蓝studyzy
2022/06/16
1.1K0
app数据库表的设计_订单数据库设计
登录相关 用户信息表(账户相关) CREATE TABLE UserAccount ( UID INT NOT NULL AUTO_INCREMENT, /* 用户ID */ ParentID INT NOT NULL, /* 父级ID */ UserName VARCHAR(40) NOT NULL, /* 用户名 */ NickName VARCHAR(40), /* 昵称 */ Avatar VARCHAR(40), /* 头像 */ Safeques VARCHAR(40), /* 安全问题 */ SafeAnswer VARCHAR(40), /* 安全问题答案 */ Locked INT NOT NULL , /* 是否锁定 */ LastVisitTime DATETIME, /最后访问时间/ RegisterTime DATETIME, /注册时间/ PRIMARY KEY (UID) ); 用户信息详情表 CREATE TABLE UserDetails ( UID INT NOT NULL REFERENCES UserAccount (UID), /* 用户ID */ Gender INT NOT NULL, /* 性别 */ RealName VARCHAR(40) NOT NULL, /* 真实姓名 */ Mobile VARCHAR(40), /* 手机号 */ Email VARCHAR(40), /* 邮箱 */ BirthDate DATETIME, /* 出生日期 */ IDCard VARCHAR(40) NOT NULL, /* 身份证号 */ Address VARCHAR(40) NOT NULL, /* 地址 */ PlateNum VARCHAR(40) NOT NULL /* 车牌号 */ );
全栈程序员站长
2022/10/02
5620
关系数据库、数据库的设计(数据库学习)
-|关系的数学定义:域(同类型值集合)、由笛卡儿积(任意域各自相乘)推出关系的定义
营琪
2019/11/04
2.1K0
数据库设计
1)信息需要:表示一个组织部门需要的数据及其结构。主要定义将要设计的数据库系统用到的所有信息,包括描述实体、属性、联系的性质,数据之间的联系。
ellipse
2019/08/16
1.1K0
数据库设计
数据库设计
数据库设计 数据库设计步骤 收集信息 与该系统有关人员进行交流、座谈,充分了解用户需求,理解数据库需要完成的任务 标识实体 (Entity) 标识数据库要管理的关键对象或实体,实体一般是名词 标识每个实体的属性(Attribute) 标识实体之间的关系(Relationship) 三大范式 第一范式的目标是确保每列的原子性 第二范式要求每个表只描述一件事情 第三范式如果一个关系满足2NF,并且除了主键以外的其他列都不传递依赖于主键列
xiaozhangStu
2023/05/04
3910
数据库设计的步骤
数据库设计是指:根据用户的需求,在数据库管理系统上(比如:MySQL、Oracle),设计数据库的结构和建立数据库的过程。
真正的飞鱼
2023/03/19
8710
数据库设计
数据库设计(Database Design)是指对于一个给定的应用环境,构造最优的数据库模式,建立数据库及其应用系统,使之能够有效地存储数据,满足各种用户的应用需求(信息要求和处理要求)。在数据库领域内,常常把使用数据库的各类系统统称为数据库应用系统。 数据库设计的设计内容包括:需求分析、概念结构设计、逻辑结构设计、物理结构设计、数据库的实施和数据库的运行和维护。
星哥玩云
2022/09/15
5600
数据库设计
举个例子: 按上面出现过的图, Students(sid, Iname, fname, midiaitia)
Rikka
2022/01/19
3.2K0
数据库设计
数据库设计
数据模型(Data Model)是数据特征的抽象,包括数据的结构部分、数据的操作部分和数据的约束条件。
Gujiu
2023/10/19
2290
数据库设计
杨鑫奇数据库设计经验之谈 一个成功的管理系统,是由:[50% 的业务 + 50% 的软件] 所组成,而 50% 的成功软件又有 [25% 的数据库 + 25% 的程序] 所 组成,数据库设计的好坏是一个关键。如果把企业的数据比做生命所必需的血液,那么数据库的设计就是应用中最重要的一部分。有关数据库设计的材料汗牛充栋, 大学学位课程里也有专门的讲述。不过,就如我们反复强调的那样,再好的老师也比不过经验的教诲。所以我归纳历年来所走的弯路及体会,并在网上找了些对数据 库设计颇有造诣的专业人士给大家传授一些设计数据
赵小忠
2018/01/24
1.1K0
基于实验的lncRNA功能汇总数据库
目前大部分lncRNA相关的数据库都是依赖高通量测序,而今天我们介绍的这个数据库以实验验证为基础,收集2016年5月1日前的所有lncRNA实验数据,并整合了lncRNAdb, LncRANDisease, Lnc2Cancer 和 PLNIncRBase 三个lncRNA数据库的结果,当前版本包含来自77个物种的1543个lncRNAs,是目前为止最全面的有实验结果支持的lncRNA数据库,EVLncRNAs(http://biophy.dzu.edu.cn/EVLncRNAs/)。
医学数据库百科
2020/07/14
4810
【数据库】实验2 单表查询
1.熟练掌握SQL Server查询分析器的使用方法,加深对标准SQL查询语句的理解。
韩旭051
2020/06/22
9910
EVLncRNAs:最大的实验验证过的lncRNA数据库
在已有的lncRNA数据库中,包含了两种类型的lncRNA, 一种是实验手段证实过的lncRNA, 另外一种是软件预测出来的lncRNA,其中软件预测的结果是存在很多的假阳性的。
生信修炼手册
2019/12/19
4390
EVLncRNAs:最大的实验验证过的lncRNA数据库
数据库设计概念结构设计_数据库设计典型实例
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
全栈程序员站长
2022/11/04
1.2K0
数据库设计概念结构设计_数据库设计典型实例

相似问题

利用关系数据库跟踪实验数据的演化

11

数据输入跟踪(数据库设计)

10

数据集+实验运行跟踪

20

数据库设计:跟踪记录更改

40

跟踪会员登录数据库设计

22
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文