【C#】继承和序列化

news2025/4/7 3:13:47

前言

        在之前的一篇文章中:

【C#】复杂Json的反序列 + 任意Json获取_code bean的博客-CSDN博客其中result这个key对应的内容是可能发生变化的,所以这里可以用到泛型。如何将一个复杂类型的JSON进行反序列化。那就是如何把json拆解成一个个子类的过程。https://blog.csdn.net/songhuangong123/article/details/126842695?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522168411610816782425112498%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=168411610816782425112498&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-126842695-null-null.article_score_rank_blog&utm_term=json&spm=1018.2226.3001.4450#:~:text=%E3%80%90C%23%E3%80%91%E5%A4%8D%E6%9D%82Json%E7%9A%84%E5%8F%8D%E5%BA%8F%E5%88%97%20%2B%20%E4%BB%BB%E6%84%8FJson%E8%8E%B7%E5%8F%96也讲到的Json序列化,使用的了微软自带的库:

这次我不得不再次用回 :

原因是, 在 .NET 7 之前的版本中,System.Text.Json 不支持多态类型层次结构的序列化。这就太坑了,我还在使用.net6啊!!! 算了还是用回老牌库吧,这个和 .NET版本不存在冲突。

背景

那问题来了,为啥我需要支持多态类型层次结构的序列化呢?原因是这样的,目前写了一很多工具类,本着遵循 do not copy your self 的原则,我使用了继承。一堆工具集成一个工具类。

所以在序列化的时候,我的数据结构中使用的类型是基类,而指向的对象是子类。而在使用System.Text.Json的时候发现,序列化后的内容是父类的类容,而子类的部分并没有序列化。这相当于数据丢失了! 所以我需要“支持多态类型层次结构的序列化”。当更换为Newtonsoft.Json之前,序列化时子类的部分就得以保存成功。

自定义反序列化

接着,另一个问题来了,反序列化出问题了,因为我们保存的是子类对象,反序列化时,数据结构中任然是父类,这次程序无法得知 反序列化的这个子类到底是哪个子类,所以反序列化失败。为此,我们必须实现自定义反序列化,指定反序列化时子类类型。

继承JsonConverter

public class ToolJsonConverter : JsonConverter
{
        //控制哪些类型要序列化,哪些不需要! 
        public override bool CanConvert(Type objectType)
        {
            return true;
        }
        public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
        {                              
        }
        /// <summary>
        /// 如果为false,将不会触发下面这个WriteJson!会走默认的反序列化
        /// </summary>
        public override bool CanWrite => false;
        public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
}

我们自定义一个类继承JsonConverter,继承这个类需要实现三个方法

1 CanConvert 针对序列化,控制哪些类型要序列化,哪些不需要! 我这里直接返回true表示全部都序列化,但是我们可以通过使用[JsonIgnore]特性,修饰不需要序列化的类。(ps:由于两个库里都有这个[JsonIgnore]特性,注意不要使用到System.Text.Json中的[JsonIgnore]

2 ReadJson 反序列化时,会调用该接口。

3 WriteJson 序列化时,调用!

但是,目前默认的序列化已经满足了我的要求,所以我不希望调用这个函数,默认的就好,那么做呢?答案是。重写属性CanWrite,让其变为false.

/// <summary>
/// 如果为false,将不会触发下面这个WriteJson!会走默认的反序列化
/// </summary>
public override bool CanWrite => false;

那关键就是第二步ReadJson 如何编写,这里先暂停一下。先暂时认为这个自定义的类已经完成了。这个类如何使用呢?

知识点补充

JsonSerializerSettings,这个可以控制序列化时的一些,细节,比如解决序列化时中文乱码的问题,比如,序列化时我需要格式化文本:

我们可以这么做:

static public JsonSerializerSettings options;

static JsonConfigCtrl()
{
    options = new JsonSerializerSettings();
    options.Formatting = Formatting.Indented; //格式化
    options.Culture = new System.Globalization.CultureInfo("zh-CN"); //解决中文乱码
}

我们还可以添加自定义序列化,也就是我们定义的继承JsonConverter的类(toolJsonConverter)。

options.Converters.Add(toolJsonConverter);

这里是添加,而不是赋值,说明可以添加多个。这样就能针对不同类,进行不用方案的反序列化。

第一步

  通过JsonSerializerSettings添加自定义的类对象  。

 添加自定义序列化,也就是我们定义的继承JsonConverter的类(toolJsonConverter)。

options.Converters.Add(toolJsonConverter);

让后在反序列化的时候,传入options参数:

string str = JsonConvert.SerializeObject(obj, options);

第二步

我们需要找到工具的基类,然后修饰它:[JsonConverter(typeof(ToolJsonConverter))]

如图:

 这样,我们在反序列的时候,如果遇到了 BaseToolObj类就会调用ToolJsonConverter中重写的ReadJson的函数:

public class ToolJsonConverter : JsonConverter
    {
        //控制哪些类型要序列化,哪些不需要! 
        public override bool CanConvert(Type objectType)
        {
            //throw new NotImplementedException();
            
            return true;
        }

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

                //string full_dll_path = jsonObject.GetValue("mModInfo.FullDllPath").ToString();
                JObject mModInfo = (JObject)jsonObject.GetValue("mModInfo");
                string full_dll_path = mModInfo.GetValue("FullDllPath").ToString();

                Assembly assembly = Assembly.LoadFrom(full_dll_path.ToString());
                var ToolClassName = mModInfo.GetValue("ToolClassName")?.ToString();

                //获取对象类名称
                var full_name = assembly.DefinedTypes.First(e => e.Name == ToolClassName).FullName;
                //反射获得对象
                var bto = assembly.CreateInstance(full_name);
                //将json的值赋予对象
                serializer.Populate(jsonObject.CreateReader(), bto);
                             
                return bto;
            }
            catch (Exception ex)
            {
                MessageBox.Show("自定义序列化(ToolJsonConverter)失败,配置文件可能损坏!" + ex.Message);
                return null;
            }

            
            
        }



        /// <summary>
        /// 如果为false,将不会触发下面这个WriteJson!会走默认的反序列化
        /// </summary>
        public override bool CanWrite => false;


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

在 ReadJson 中,我首先利用反射得到子类对象,然后通过:
serializer.Populate(jsonObject.CreateReader(), bto); 将json的值一一对应赋值给对象! 然后将这个对象返回,这样基类就会指向这个子类对象了。

注意,我的数据结构中,有一个列表里面有多个BaseToolObj,所以ReadJson这个函数是会被多次调用的,var jsonObject = JObject.Load(reader); 得到的jsonObject也仅仅是BaseToolObj对应的部分,和其他的数据结构无关。这也是继承了JsonConverter的魅力所在。让我们只用关心被特性[JsonConverter(typeof(ToolJsonConverter))] 修饰的类。

小结

1 序列化过程,比较简单基本默认就好,不过需要,通过JsonSerializerSettings 做一些全局设置,比如添加自定义的序列化等。

2 反序列化时,需要得知子类的类型,然后返回一个子类类型,这样就等将父类指向之类类型了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/527569.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

NLP 中语言表示 (向量化) 的基本原理和历史演变综述

目录 1 前言2 语言表示2.1 离散表示2.1.1 独热编码2.1.2 词袋模型2.1.3 TF-IDF 模型2.1.4 N-gram 模型2.1.5 基于聚类的表示 2.2 连续表示2.2.1 分布式表示2.2.2 Word Embedding2.2.2.1 Word2Vec2.2.2.2 GloVe2.2.2.3 FastText 2.2.3 基础神经网络模型2.2.3.1 神经词袋模型2.2.…

Excel 设置只能输入指定的字符

目录 1. 创建你要用的表格 2. 确定你要限定输入的行/ 列 3. 创建另一个sheet&#xff0c;用来保存限制输入的配置信息 4. 选中【是否外包】列&#xff0c;并选择数据验证 5. 设置数据限制 6. 确认结果 7. 不想设置配置sheet怎么办&#xff1f; 在工作中&#xff0c;你们…

基于Java+SpringBoot+vue+node.js的图书购物商城系统详细设计和实现

基于JavaSpringBootvuenode.js的图书购物商城系统详细设计和实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获取源码…

70.建立一个轮播图组件第一部分

本次我们的目标是实现如图所示的 初始代码如下&#xff1a; ● 现在我们把图片、文本、按钮等元素添加进去 <div class"carousel"><img src"maria.jpg" alt"Maria de Almeida" /><blockquote class"testimonial">&…

一、Go基础知识入门

1、go语言介绍 2、go开发环境搭建 2.1、go的安装 go下载地址&#xff1a;All releases - The Go Programming Language&#xff0c;windows选择下载go1.20.2.windows-amd64.msi文件。 双击go1.20.2.windows-amd64.msi&#xff0c;点击"Next"&#xff0c;然后勾选同…

开启自主创新基础设施领先之路,超融合缘何能担当大任?

数字基础设施领域最重要的趋势都有哪些&#xff1f; 毫无疑问&#xff0c;超融合便是其中之一。Gartner《2022年中国ICT技术成熟度曲线报告》&#xff08;Hype Cycle for ICT in China, 2022&#xff09;预测&#xff0c;超融合技术未来2年内将到达“生产力成熟期”&#xff0…

2023企业数智化财务创新峰会西安站圆满举办

5月11日&#xff0c;“初夏之际从头越&#xff0c;数智财务待有时。”由用友主办的「智能会计 价值财务」2023企业数智化财务创新峰会 西安站圆满举办&#xff01;西安交通大学管理学院副院长、教授、博士生导师田高良&#xff0c;山东高速集团有限公司财务共享中心收入核算部…

面向Java开发者的ChatGPT提示词工程(2)

在这篇博客文章中&#xff0c;我将分享一些关于提示词的关键原则&#xff0c;帮助你在使用语言模型时获得更好的结果。具体来说&#xff0c;我将介绍两个关键原则&#xff0c;帮助你编写有效的提示词。同时&#xff0c;我也鼓励你在阅读文章的过程中运行代码&#xff0c;亲自体…

浅谈IDC数据中心综合布线第二篇——结构化布线

数据中心网络在当今的业务中扮演着越来越重要的作用&#xff0c;提供数据的存储、管理、共享、交换、应用等功能。在数据中心中&#xff0c;大量的数据在服务器、交换机、存储设备之间通过物理层的光缆&#xff08;仅讨论光纤布线&#xff09;进行传输。数据表明&#xff0c;在…

java Collection 所有单列集合的父接口

为了在程序中可以保存数目不确定的对象或数据&#xff0c; Java提供了一系列特殊的类&#xff0c;这些类可以存储任意类型的对象&#xff0c; 并且长度可变&#xff0c;这些类被统称为集合。集合类都位于java.util包中&#xff0c; 使用时必须导包。集合按照其存储结构可以分为…

微信小程序开发之获取用户信息

环境 微信开发者工具 Stable 1.06.2303220云开发控制台 v1.5.47 用户的openid和头像名称信息 openid 是小程序用户的唯一标识。注意&#xff0c; openid 并不是微信用户的唯一标识&#xff0c;它是和小程序绑定的。也就是说&#xff0c;同一个微信用户&#xff0c;他在小程序…

【Unity-UGUI控件全面解析】| Dropdown 下拉菜单组件详解

🎬【Unity-UGUI控件全面解析】| Dropdown 下拉菜单组件详解一、组件介绍二、组件属性面板三、代码操作组件四、组件常用方法示例4.1 监听开关事件4.2 添加删除节点💯总结🎬 博客主页:https://xiaoy.blog.csdn.net 🎥 本文由 呆呆敲代码的小Y 原创,首发于 CSDN🙉 �…

alembic迁移

alembic 作用 alembic是sqlalchemy的作者开发的。用来做OMR模型与数据库的迁移与映射。alembic使用方式跟git有点了类似&#xff0c;表现在两个方面。 第一个&#xff0c;alembic的所有命令都是以alembic开头 第二&#xff0c;alembic的迁移文件也是通过版本进行控制的。首先…

java版Spring Cloud+SpringBoot+mybatis+uniapp b2b2c 多商户入驻商城 直播 电子商务

J2EE企业分布式微服务云快速开发架构 Spring CloudSpring Boot2MybatisOauth2ElementUI 前后端分离 1. 鸿鹄Cloud架构清单 2. Commonservice&#xff08;通用服务&#xff09; 通用服务&#xff1a;对spring Cloud组件的使用&封装&#xff0c;是一套完整的针对于分布式微…

程序员加班一周总结出可视化大屏效果,9种炫酷组件打包带走!

前段时间参加行业分享交流会&#xff0c;听各位大佬的经验传授&#xff0c;其中有一位用一个极度炫酷的可视化大屏进行展示&#xff0c;可谓是让人眼前一亮。我总是在冲浪的时候看到大屏内容&#xff0c;现场的亲眼目睹大屏真是无比震撼的&#xff0c;于是我马上抓住机会向人家…

Quarkus + mybatis + mybatis-generator 使用总结

Quarkus mybatis mybatis-generator 使用总结 大纲 1 Quarkus结合mybatis 2 Quarkus手动配置数据源 3 Quarkusmybatis的使用 4 使用mybatis-generate 5 使用mybatis-generate后的问题 基础说明 1 开发环境 window112 GraalVM 版本22.3.0 3 quarkus 版本 2.13.7.Final4 myb…

【小韬讲存储】——自动精简配置

ChatGPT全球大火 网友们纷纷登陆尝试它的功能 面对五花八门的问题&#xff0c;ChatGPT都能够给出高情商答案 而答案的背后是百TB数据的分析、训练 对于百TB测试数据 企业不会选择一次性购买所需硬件 而是根据实际所需容量进行多次购买 产品背后的百TB数据容量压力 在当前…

火山引擎DataTester:A/B实验平台数据集成技术分享

DataTester的数据集成系统&#xff0c;可大幅降低企业接入A/B实验平台门槛。 当企业想要接入一套A/B实验平台的时候&#xff0c;常常会遇到这样的问题&#xff1a; 企业已经有一套埋点系统了&#xff0c;增加A/B实验平台的话需要重复做一遍埋点&#xff0c;费时费力&#xff1b…

Android Jetpack Compose中derivedStateOf{}与remember{} with keys的区别

Android Jetpack Compose中derivedStateOf{}与remember{} with keys的区别 在这篇短文中&#xff0c;我将清楚地解释derivedStateOf{}和使用带有keys的remember{}之间的区别。阅读完本文后&#xff0c;你将对它们之间的区别有非常清晰的认识。 先决条件 为了理解本文&#xf…

Java实现自定义字段

Java自定义字段 小黄最近在工作中遇到一个比较有意思的需求&#xff0c;在此跟大家分享一下 需求 这个需求是这样的&#xff0c;用户在添加表单时&#xff0c;除了一些固定信息填入之外&#xff0c;还可以自定义一些字段填入&#xff0c;例如一个用户表&#xff0c;默认情况下…