Unity中Newtonsoft.Json的使用(三)_unity newtonsoft.json jobject-程序员宅基地

技术标签: unity  Unity  json  

上期(Unity中Newtonsoft.Json的使用(二))讲完了对Newtonsoft.Json序列化反序列化的一些常用设置,这期将教大家解决一个很多同学在使用Json时常会遇到的一个问题:派生类数据丢失。

1.Json中派生类字段丢失问题

我们先来测试一下吧

先定义一下带继承关系的数据结构,分别是生物Creature基类,包含通用的属性id和name;猪Pig子类,养猪我们比较关心长多重了可以吃了没;竹子Bamboo子类,竹子我们关心它的高度,是否可以做家具了。

/// <summary>
/// 生物
/// </summary>
public class Creature
{
    public int id;          //id编号
    public string name;     //生物名字
}

/// <summary>
/// 猪
/// </summary>
public class Pig : Creature
{
    public float weight;    //重量
}

/// <summary>
/// 竹子
/// </summary>
public class Bamboo : Creature
{
    public float height;    //高度
}

写一个测试类,看一下序列化结果

private void Start()
    {
        List<Creature> creatureDatas = new List<Creature>();

        Creature pig = new Pig()
        {
            id = 10086,
            name = "小猪佩奇",
            weight = 300,
        };

        Creature bamboo = new Bamboo()
        {
            id = 10010,
            name = "节节高",
            height = 10,
        };
        creatureDatas.Add(pig);
        creatureDatas.Add(bamboo);

        string json = JsonMgr.Serialize(creatureDatas);
        Debug.Log(json);
    }

可以看到序列化没什么问题,包含了所有数据

好,继续加上反序列的代码

private void Start()
    {
        List<Creature> creatureDatas = new List<Creature>();

        Creature pig = new Pig()
        {
            id = 10086,
            name = "小猪佩奇",
            weight = 300,
        };

        Creature bamboo = new Bamboo()
        {
            id = 10010,
            name = "节节高",
            height = 10,
        };
        creatureDatas.Add(pig);
        creatureDatas.Add(bamboo);

        string json = JsonMgr.Serialize(creatureDatas);
        Debug.Log(json);

        List<Creature> newCreateDatas = JsonMgr.DeSerialize<List<Creature>>(json);
        Debug.Log(JsonMgr.Serialize(newCreateDatas));
    }

再看一些下序列化的结果,发现什么问题没有

我们发现子类Pig的weight和子类Bamboo的height这两个专属字段的数据都丢失了,为什么会发生这样的事情呢?因为我们在反序列化时指定的类型是基类Creature的,反序列化时只会去处理Creature中有的字段。

如果我们想处理单个数据,只需要指定成具体的子类类型就行了,比如反序列化Pig类型时指定成Pig类型而不是Creature就可以反序列化出Pig中的weight字段了。

但是我们通常来说并不会单独地进行子类的使用,因为要符合依赖倒置原则和里氏替换原则,且不同子类可能会用同一个容器进行缓存,或者包含嵌套关系使用,这时候就没办法指定所有的子类类型了。通常来说声明时使用的更多还是基类的类型。

接下来就教大家对Newtonsoft.Json进行扩展来解决这样的问题。

2.扩展Newtonsoft.Json来反序列化

首先编写一个反序列化的基类DataCreationConverter,继承自JsonCnverter,该库来源于这位大佬的文章

C#基类json反序列化为某个派生类,派生类属性不丢失

using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

/// <summary>
/// Newtonsoft.json数据反序列化转换器
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class DataCreationConverter<T> : JsonConverter
{
    /// <summary>
    /// Create an instance of objectType, based properties in the JSON object
    /// </summary>
    /// <param name="objectType">type of object expected</param>
    /// <param name="jObject">
    /// contents of JSON object that will be deserialized
    /// </param>
    /// <returns></returns>
    protected abstract T Create(Type objectType, JObject jObject);

    public override bool CanConvert(Type objectType)
    {
        return typeof(T).IsAssignableFrom(objectType);
    }

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

        // Create target object based on JObject
        T target = Create(objectType, jObject);

        // Populate the object properties
        serializer.Populate(jObject.CreateReader(), target);

        return target;
    }

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

    protected bool FieldExists(JObject nJObject, string nPropertyName)
    {
        return nJObject[nPropertyName] != null;
    }

    protected bool FieldExists(string nFieldName, JObject nJObject, out string nEntityVel)
    {
        nEntityVel = nJObject[nFieldName] == null ? "" : nJObject[nFieldName].ToString();
        return nJObject[nFieldName] != null;
    }
}

这个类的原理就是在反序列化时识别子类的专属字段来判断是哪个子类,比如识别到Pig专属的weight字段就说明是Pig类型

然后我们针对Creature类写一个继承自DataCreationConverter的反序列化转换器

public class CreatureDataConverter : DataCreationConverter<Creature>
{
    protected override Creature Create(Type objectType, JObject jObject)
    {
        //判断属性值来确认是哪个子类
        if (FieldExists(jObject, "weight"))
        {
            return new Pig();
        }
        else if (FieldExists(jObject, "height"))
        {
            return new Bamboo();
        }
        else
        {
            return new Creature();
        }
    }
}

反序列化时传入转换器

public static T DeSerialize <T>(string json, JsonConverter[] jsonConverters)
    {
        return JsonConvert.DeserializeObject<T>(json, jsonConverters);
    }
private void Start()
    {
        List<Creature> creatureDatas = new List<Creature>();

        Creature pig = new Pig()
        {
            id = 10086,
            name = "小猪佩奇",
            weight = 300,
        };

        Creature bamboo = new Bamboo()
        {
            id = 10010,
            name = "节节高",
            height = 10,
        };
        creatureDatas.Add(pig);
        creatureDatas.Add(bamboo);

        string json = JsonMgr.Serialize(creatureDatas);
        Debug.Log(json);
        JsonConverter[] jsonConverters = new JsonConverter[1] {
            new CreatureDataConverter(),
        };
        List<Creature> newCreateDatas = JsonMgr.DeSerialize<List<Creature>>(json, jsonConverters);
        Debug.Log(JsonMgr.Serialize(newCreateDatas));
    }

可以看到现在子类数据完完整整地反序列化出来了

简单小结

本期教大家解决了Newtonsoft.Json中使用基类进行反序列化造成派生类专属数据丢失问题,到此,Newtonsoft.Json中所有常见的用法都已经教给了大家。

如果大家在使用Newtonsoft.Json时遇到了什么问题,也欢迎在评论区进行讨论~

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/he153422079/article/details/137227107

智能推荐

工作几年还是悟不懂自动化测试的意义_接口自动化介入时间点-程序员宅基地

文章浏览阅读858次,点赞11次,收藏25次。James Bach 曾经在一篇博文提到,自动化测试这个名字是非常有误导性的。它让一般的人误以为就是测试完全被自动化了,就像一个自动的咖啡机一样,我只需要把杯子放在那里,按一个button就够了。James说更加准确的叫法应该是“工具辅助的测试”。当然他还有另一层意思,就是好的测试用例是没有办法100%被自动化的,测试人员的经验,逻辑判断和探索性的测试方法都不能被有效自动化。我非常同意这个观点。

【JAVA长虹键法】第三式 简单工厂模式(23种设计模式)_长虹java面试-程序员宅基地

文章浏览阅读1k次,点赞25次,收藏30次。【JAVA长虹键法】主要讲了23种设计模式,本系列专栏会以虹猫蓝兔七侠传的故事为例来给大家详细分析所有模式,希望能给大家带来帮助!简单工厂模式一个天外陨石(抽象产品),三把剑(产品),一个铸剑师(工厂)。虹猫蓝兔莎莉分别找铸剑师造了三把剑。定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中。这满足创建型模式中所要求的“创建与使用相分离”的特点。1、按实际业务场景划分,工厂模式有 3 种不同的实现方式,分别是简单工厂模式、工厂方法模式和抽象工厂模式。

jquery.base64.js-程序员宅基地

文章浏览阅读1.5k次。(function($) { $.base64 = function(options) { var defaults = { data:"", type:0, unicode:true }; var opts = $.extend(defaults,op..._jquery.base64.js

源码编译libyuv_libyuv源码-程序员宅基地

文章浏览阅读432次,点赞4次,收藏9次。libyuv 是常用的处理YUV数据的库,例如将YUV进行缩放。_libyuv源码

vue 水印组件_vue 水印插件-程序员宅基地

文章浏览阅读2.2k次,点赞4次,收藏5次。vue2 水印效果,使用MutationObserver监听元素结构,支持水印防篡改。_vue 水印插件

什么是分布式系统,这么讲不信你不会-程序员宅基地

文章浏览阅读336次。戳蓝字“CSDN云计算”关注我们哦!我曾在网络上搜索过”如何学习分布式系统“,也在知乎上关注了该话题,但并没有看到一个全面的、有指导意义的答案。本文的目标是给打算全面学习分布式系统的自己..._分布式系统的基本概念和原理

随便推点

layer.open()的content属性传参数方法_layer.open content-程序员宅基地

文章浏览阅读3.9w次,点赞4次,收藏20次。最近接触到layer弹窗,感觉弹窗功能异常强大,真的很方便,所以记录下来;1.layer官网:http://layer.layui.com/在这里下载需要的js2.语法:layer.open(options)3.实例:var index = layer.open({ content: 'test'}); //拿到的index是一个重要的凭据,它是诸如layer.clo..._layer.open content

Android BLE设备蓝牙通信框架BluetoothKit-程序员宅基地

文章浏览阅读814次,点赞19次,收藏13次。一、统一解决Android蓝牙通信过程中的兼容性问题二、提供尽可能简单易用的接口,屏蔽蓝牙通信中的技术细节,只开放连接,读写,通知等语义。三、实现串行化任务队列,统一处理蓝牙通信中的失败以及超时,支持可配置的容错处理四、统一管理连接句柄,避免句柄泄露五、方便监控各设备连接状态,比如手机可同时连接的设备数有限,可以检测设备连接活跃度,在尽可能维持连接的情况下,将最不活跃的设备自动断开。六、支持多进程APP架构下蓝牙连接的管理七、支持拦截所有对蓝牙原生接口的调用。

flutter学习(一)——安装flutter并配置环境_安装flutter环境visual studio需要下载什么依赖-程序员宅基地

文章浏览阅读7.4k次。文章目录一、下载flutter安装包二、flutter doctor三、配置编辑器一、下载flutter安装包中文文档:https://flutter.cn/docs/get-started/install/windowslink下载安装包解压到指定目录,我解压的目录是D盘下的software把flutter中的bin目录添加至环境变量在左下角搜索env,打开系统环境变量设置(如果修改环境变量之前打开了cmd,就重新打开另一个cmd打开验证)在cmd中验证flutter是否安装完成_安装flutter环境visual studio需要下载什么依赖

干货丨如何优雅地设计并控制一台协作机械臂-程序员宅基地

文章浏览阅读4.2k次,点赞7次,收藏63次。“本期技术干货,我们邀请到了小米机器人实验室工程师任赜宇,和大家分享如何去设计并控制一台协作机械臂。”一、前言协作机械臂,顾名思义,是适合与人类通力协作去解决实际问题的一类机械臂,作为机械臂家族的一员,与传统的工业机械臂相对应。工业机械臂经过多年的发展,在汽车、3C电子等工业自动化领域已经得到了广泛的落地与应用,而协作机械臂作为近几年来的新兴产物,在智能性、安全性与易用性..._机械臂感知 整体框架

mysql pager用不了_mysql pager 妙用!-程序员宅基地

文章浏览阅读72次。分页显示。mysql> pager lessPAGER set to 'less'mysql> show engine innodb status\G[...]退出pagermysql> pagerDefault pager wasn't set, using stdout.ormysql> \nPAGER set to stdout一些其他的用法mysql> pag..._pager has been disabled.

CS5265 USB-C to HDMI 4k@60Hz单转方案-程序员宅基地

文章浏览阅读212次。HDMI接口包括4个最小化传输差分信号时钟/数据对、DDC和HPD信号,支持高达6Gpbs的数据速率,足以处理FHD 1080p 120Hz和UHD 4k 60Hz视频分辨率。此外,它还包含支持HDCP1.4和HDCP2.3得HDCP引擎,嵌入式密钥提供最高级别的HDCP密钥安全性,确保安全传输受保护的内容。TypeC转HDMI音视频IC,TYPEC转HDMI带PD快充,TYPEC扩展坞方案,TYPEC转HDMI方案,TYPEC转HDMI2.0转换器。每个通道的更大数据速率高达6-Gps。

推荐文章

热门文章

相关标签