首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >如何反序列化包含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

复制
相关文章
Python中gdal实现多幅栅格影像批量绘制直方图
  现需要对多幅栅格数据文件进行直方图绘制,具体绘制内容即各栅格图像像素数值的分布情况;所有栅格数据都保存在同一目标路径下,且均为.tif格式;而目标路径下具有其它非.tif格式的文件,以及不需要进行直方图绘制的.tif格式文件,因此需要在绘制前对目标路径下的文件列表加以筛选,只保留需要绘制直方图的栅格文件。
疯狂学习GIS
2023/07/09
2870
Python中gdal实现多幅栅格影像批量绘制直方图
ROC曲线绘制原理及如何用SPSS绘制ROC曲线
ROC曲线(Receiver operating characteristic curve),即受试者工作特征曲线,主要用来评价某个指标对两类被试(如病人和健康人)分类/诊断的效果,以及寻找最佳的指标临界值使得分类效果最好。但是ROC曲线绘制的原理是什么,或者说如何一步步画出ROC曲线,以及如何用SPSS软件快速绘制出ROC曲线呢?对于很多新手朋友来说,对上述问题并不十分清楚。笔者这里对上述问题进行详细阐述,以期大家对ROC曲线有更深入的了解。
悦影科技
2020/11/18
5K0
ROC曲线绘制原理及如何用SPSS绘制ROC曲线
如何用Python代码绘制赏月美景?
使用turtle库绘制月亮、云朵、山以及古诗,游戏模块使用pygame库,配上美美的背景音乐。
芯动大师
2022/11/15
6010
如何用Python代码绘制赏月美景?
Python中gdal读取多波段HDF栅格影像并绘制直方图
  本文详细介绍基于Python语言gdal等模块实现多波段HDF栅格图像文件(即.hdf文件)的读取、处理与像元值可视化等操作。此外,基于gdal等模块读取.tif格式栅格图层文件的方法可以查看Python中gdal实现多幅栅格影像批量绘制直方图,读取单波段.hdf格式栅格图层文件的方法可以查看Python中gdal栅格影像读取计算与写入及质量评估QA波段筛选掩膜。
疯狂学习GIS
2021/08/13
1.2K0
如何用Origin绘制平行坐标图
今天有同学问我,Origin是否可以做如下的图,也就是医学中常见的一幅从成分到靶标再到通路的一幅图。我打开Origin用数据试了试,可以的,没问题。不需要使用R工具就可以实现,那么今天我们就来说说这个图怎么来做。
百味科研芝士
2020/04/30
2.7K0
如何用Origin绘制平行坐标图
【说站】如何用python绘制彩色蟒蛇
本文教程操作环境:windows7系统、Python 3.9.1,DELL G3电脑。
很酷的站长
2022/11/23
2.5K0
【说站】如何用python绘制彩色蟒蛇
软件测试|如何用Python绘制雷达图
我有朋友问我,他准备买车,预算20-25万,他在考虑几个车,说现在很难做出决定,让我帮他参谋参谋,该买哪个?
霍格沃兹测试开发Muller老师
2023/03/05
6380
附加属性
附加属性我们早就使用过,常见的用于控件定位的Grid.Row,Grid.Column就是附加属性,那这个东西具体是什么意思呢?请设想这样的情景:一个学生,他在社团可以是社长,他在班内可以是班长,在赛场又可以是运动员,这些特定的属性,并不是每个学生都具有的,只有学生参与了或者在某个环境中,才具有这样的属性。那我们在定义学生类时,就不能把这些属性定义进去,为了解决这种在某些环境中才具有特定属性的情况,WPF引入了附加属性,附加属性就是一个对象可以被它外部的环境附加某些属性,而对象本身实际上不具有这样的属性。
宿春磊Charles
2021/11/05
8280
技术解析:如何用pyecharts绘制时间轮播图
我们依旧以python小小白的角度去解析如何用pyecharts去制作时间线轮播多图。其实在之前我也并没有使用过这个功能,仅有一点的类似经验是之前项目在Echarts中实现过类似功能,所以第一步也是打开pyecharts官方文档。找到这部分的说明
刘早起
2020/04/22
1.9K0
技术解析:如何用pyecharts绘制时间轮播图
手把手|如何用Python绘制JS地图?
编译:佘彦遥 程序注释:席雄芬 校对:丁雪 原文链接:https://github.com/python-visualization/folium/blob/master/README.rst Folium是建立在Python生态系统的数据整理(Datawrangling)能力和Leaflet.js库的映射能力之上的开源库。用Python处理数据,然后用Folium将它在Leaflet地图上进行可视化。 概念 Folium能够将通过Python处理后的数据轻松地在交互式的Leaflet地图上进行可视化展示
大数据文摘
2018/05/22
3.9K0
如何用Python的pyecharts库绘制K线图
股市及期货市场中的K线图的画法包含四个数据,即开盘价、最高价、最低价、收盘价,所有的K线都是围绕这四个数据展开,反映大势的状况和价格信息。如果把每日的K线图放在一张纸上,就能得到日K线图,同样也可画出周K线图、月K线图。研究金融的小伙伴肯定比较熟悉这个,那么我们看起来比较复杂的K线图,又是这样画出来的,本文我们将一起探索K线图的魅力与神奇之处吧!
张俊红
2021/03/22
6.1K0
如何用Python的pyecharts库绘制K线图
如何用 R 绘制动态统计图?
漫长的演化史上,人类的感官只要能有效发现食物(包含猎物),快速捕获危险信号(例如捕食者逼近),和同类高效交流(使用声音、表情或肢体语言)就大概率可以在残酷的自然淘汰赛里幸存下来。
王树义
2018/08/22
2K0
如何用 R 绘制动态统计图?
如何用Scratch 3绘制矢量图形 【Gaming】
Scratch是一种流行的用于创建视频游戏和动画的可视化编程语言。它还具有矢量绘图工具,任何人都可以使用它来创建独特的游戏和艺术。
五月Rambo
2019/11/10
5.6K0
如何用Scratch 3绘制矢量图形 【Gaming】
如何用python画一朵樱花_如何用python绘制粉色樱花
最近翻到一篇知乎,上面有不少用Python(大多是turtle库)绘制的树图,感觉很漂亮,我整理了一下,挑了一些我觉得不错的代码分享给大家(这些我都测试过,确实可以生成喔~) one 樱花树
全栈程序员站长
2022/09/27
7630
如何用python画一朵樱花_如何用python绘制粉色樱花
[CSS] 栅格化布局
栅格化布局帮助你更容易构建复杂的网页设计。它会将HTML元素转换为网格的容器(有行有列)。你可以在网格里面添加你想要的子元素。
Jimmy_is_jimmy
2020/10/29
1.2K0
数据可视化|如何用wordcloud绘制词云图?
词云图中的每个字的大小与出现的频率或次数成正比,词云图的统计意义不是特别大,主要是为了美观,用于博客和网站比较常见。
黑妹的小屋
2020/08/05
1.4K0
数据可视化|如何用wordcloud绘制词云图?
如何用Loki来绘制Ingress Nginx监控大屏
最近无意间发现Grafana官网的Dashboard页面首推了一个用Loki分析Nginx日志的页面,大体也就是Loki2.0后产品主推的LogQL V2语法的典型应用。也许是最近感受到大家愈发对新语法的不熟悉,社区也特地做了一个quick demo来简单说明其新语法的使用。
云原生小白
2021/05/13
1.9K0
如何用Loki来绘制Ingress Nginx监控大屏
如何用程序绘制一朵花?
本系列课程是针对无基础的,争取用简单明了的语言来讲解,学习前需要具备基本的电脑操作能力,准备一个已安装python环境的电脑。如果觉得好可以分享转发,有问题的地方也欢迎指出,在此先行谢过。
叶子陪你玩
2020/03/24
1.1K0
如何用程序绘制一朵花?
EntityFramework附加实体
//0.0创建修改的 实体对象 Models.BlogArticle model = new BlogArticle(); model.AId = 12; model.ATitle = "新的数据"; model.AContent = "新的数据~~~~~"; //0.1添加到EF管理容器中,并获取 实体对象 的伪包装类对象 DbEntityEntry<Models.BlogArticle> entry = db.Entry<Models.BlogArticle>(model); //**如果使用 En
liulun
2018/01/12
7570
点击加载更多

相似问题

R spplot -在具有相同颜色比例的栅格上绘制点

13

对R spplot中的栅格图进行重新排序

115

如何用spplot改变字体系列?

11

用spplot叠加绘制两个SpatialPolygonsDataFrames

10

绘制栅格板

13
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

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

洞察 腾讯核心技术

剖析业界实践案例

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