C#Object类型的索引,序列化和反序列化
前言
最近在编写一篇关于标准Mes接口框架的文章。其中有一个非常需要考究的内容时如果实现数据灵活和可使用性强。因为考虑数据灵活性,所以我一开始选取了Object类型作为数据类型,Object作为数据Value字段,String作为数据Key字段,形态与Dic的模式比较相似。但是在实际使用过程中,由于Object可以存储任意类型,但是显性类型指向Object,Type指向数据源类型。但是在进行Xml和Json序列化时候就出现了问题,Json和Xml无法序列化Object,这个非常合理,因为Object类型是没有指向的,序列化和反序列化时,无法知道你的Object类型指向哪一种类型。因为这个原因,所以我自己根据Json和XMl的数据格式编写了一套序列化和反序列化的规则。
1.方法说明
我预先设计了一个为MesProcessData的类,他里面包含一个string的索引字段,和Object的存储字段。那么我Object字段中存储的时一组新的MesProcessData的数组,在每个新的MesProcessData中又可以存储新的数据或者数组。这个方式参考来自于C#的索引机制。C# 中 . 运算符主要用于访问类或对象的成员、命名空间中的类型,对象的名字代表的是每一级的索引。那么MesName就是我所属变量的索引,object就是索引的值。在类型判断中,我们可以通过判断Object的Type是否为Array的形式去判断Object是否存储的是MesProcessData的类对象,如果是则继续递归查找,如果不是则判断当前的MesName是否是我所需要的索引。这些内容说的非常绕口,所以下面实际使用代码演示一下
2.使用方式
//将数据为Header,Body,Return的数据存储在Top中List<MesProcessData> Message = new List<MesProcessData>();List<MesProcessData> Head = new List<MesProcessData>();Head.Add(new MesProcessData { MesName = "MESSAGENAME", MesValue = dynamic.AddressInterface });Head.Add(new MesProcessData { MesName = "TRANSACTIONID", MesValue = MesApp.Instance.Const.NowTime.ToString("yyyyMMddHHmmssffff") + number });Head.Add(new MesProcessData { MesName = "MESSAGEID", MesValue = number.ToString() });Head.Add(new MesProcessData { MesName = "REPLYSUBJECTNAME", MesValue = MesApp.Instance.MyMesConfig.MesAddress + ":" + MesApp.Instance.MyMesConfig.CustomerA.Port });Message.Add(new MesProcessData { MesName = "Header", MesValue = Head.ToArray() });Message.Add(new MesProcessData { MesName = "Body", MesValue = datas.ToArray() });List<MesProcessData> MessageReturn = new List<MesProcessData>();MessageReturn.Add(new MesProcessData { MesName = "ReturnCode", MesValue = "" });MessageReturn.Add(new MesProcessData { MesName = "ReturnMessage", MesValue = "" });Message.Add(new MesProcessData { MesName = "Return", MesValue = MessageReturn.ToArray() });MesProcessData Top = new MesProcessData();Top.MesName = "Message";Top.MesValue = Message.ToArray();
//根据上面代码存入的数据,查找数据中索引为Header.MESSAGENAME的值
string MesInterface = ProcessData.FindValueByPath(new string[] { "Header", "MESSAGENAME" }, 0).ToString();
using System;
using System.Collections.Generic;
using System.Linq;namespace Const
{public class MesProcessData{public string MesName { get; set; } = "";public object MesValue { get; set; }/// <summary>/// 根据指定路径找到对应的值/// </summary>/// <param name="path">数组路径,从下一级参数开始</param>/// <param name="index">当前使用的路径开始编号。仅在函数递归时使用</param>/// <returns></returns>public object FindValueByPath(string[] path, int index = 0){if (index >= path.Length){return this.MesValue;}if (this.MesValue is Array){Array array = this.MesValue as Array;List<MesProcessData> datas = array.OfType<MesProcessData>().ToList();foreach (MesProcessData child in datas){if (child.MesName == path[index]){return child.FindValueByPath(path, index + 1);}}}return null;}/// <summary>/// 根据指定路径来修改参数值/// </summary>/// <param name="path">数组路径,从下一级参数开始</param>/// <param name="newValue">新的值</param>/// <param name="index">当前使用的路径开始编号。仅在函数递归时使用 </param>/// <returns></returns>public MesProcessData ModifyValueByPath(string[] path, object newValue, int index = 0){if (index >= path.Length){this.MesValue = newValue;return this;}if (this.MesValue is Array array){List<MesProcessData> datas = array.OfType<MesProcessData>().ToList();foreach (MesProcessData child in datas){if (child.MesName == path[index]){// 递归修改下一级节点child.ModifyValueByPath(path, newValue, index + 1);}}}return this;}public string ObjectToString(){if (this.MesValue is string strArray){return strArray;}else{return null;}}public List<MesProcessData> ObjectToData(){List<MesProcessData> datas = new List<MesProcessData>();if (this.MesValue is Array){Array array = this.MesValue as Array;datas = array.OfType<MesProcessData>().ToList();}return datas;}}}
3.序列化和反序列化
参照上面的内容我们可以分析,当判断为数组时,我们进行递归,直到递归到没有数组值为止,那么Name作为Key,MesValue作为Value。
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;namespace Model
{internal class MesJson{public static T DeserializeObject<T>(string json){return JsonConvert.DeserializeObject<T>(json);}public static string SerializeObject<T>(T Data){return JsonConvert.SerializeObject(Data);}/// <summary>/// 反序列化为 MesProcessData/// </summary>/// <param name="Json"></param>/// <returns></returns>public static MesProcessData DeserializeJson(string Json){// 解析 JSON 字符串为 JObjectJObject jsonObject = JObject.Parse(Json);MesProcessData data = new MesProcessData();// 开始遍历解析 JSON 对象data = TraverseJsonNodes(jsonObject);return data;}private static MesProcessData TraverseJsonNodes(JObject jsonObject){MesProcessData data = new MesProcessData();data.MesName = jsonObject.Path;if (jsonObject.Count == 1){data.MesValue = jsonObject.First.ToString();}List<MesProcessData> datas = new List<MesProcessData>();foreach (var item in jsonObject){if (item.Value.Type == JTokenType.String){MesProcessData Jdata = new MesProcessData();Jdata.MesName = item.Key.ToString();Jdata.MesValue = item.Value.ToString();datas.Add(Jdata);}elsedatas.Add(TraverseJsonNodes((JObject)item.Value));}data.MesValue = datas.ToArray();return data;}private static readonly object Lock = new object();/// <summary>/// 将传入的 Object 对象序列化为 JSON 格式/// </summary>/// <param name="obj"></param>/// <returns></returns>public static string SerializeToJson(object obj){try{lock (Lock){StringBuilder sb = new StringBuilder();SerializeObject(obj, sb);return sb.ToString();}}catch (Exception ex){MesLog.Error("Mes Json序列化失败:" + ex.ToString());return "";}}private static void SerializeObject(object obj, StringBuilder sb){if (obj == null){sb.Append("null");return;}Type type = obj.GetType();if (type.IsPrimitive || type == typeof(string)){sb.Append(JsonValue(obj));return;}if (type.IsArray){sb.Append("[");Array array = (Array)obj;for (int i = 0; i < array.Length; i++){if (i > 0){sb.Append(",");}SerializeObject(array.GetValue(i), sb);}sb.Append("]");return;}sb.Append("{");sb.AppendLine();FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);bool first = true;foreach (FieldInfo field in fields){object fieldValue = field.GetValue(obj);if (fieldValue == null){continue;}if (!first){sb.Append(",");sb.AppendLine();}first = false;sb.Append($"\"{field.Name}\": ");SerializeObject(fieldValue, sb);}sb.AppendLine();sb.Append("}");}private static string JsonValue(object obj){if (obj == null){return "null";}if (obj is string str){return $"\"{EscapeString(str)}\"";}if (obj is bool boolValue){return boolValue.ToString().ToLower();}if (obj is char){return $"\"{obj}\"";}return obj.ToString();}private static string EscapeString(string str){StringBuilder sb = new StringBuilder();foreach (char c in str){if (c == '\\' || c == '"'){sb.Append('\\');}sb.Append(c);}return sb.ToString();}}
}
using JOJO.Mes.Const;
using JOJO.Mes.Log;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;namespace JOJO.Mes.Model
{internal class MesXml{/// <summary>/// 不带反馈的发送信息/// </summary>/// <param name="socket"></param>/// <param name="obj"></param>public static async void SendObjectAsXml(Socket socket, string xmlString){try{byte[] xmlBytes = Encoding.UTF8.GetBytes(xmlString);await Task.Run(() =>{// 通过Socket发送数据socket.Send(xmlBytes, 0, xmlBytes.Length, SocketFlags.None);});}catch (Exception ex){MesLog.Error("发送不带反馈的Socket数据失败:" + ex.ToString());}}public static T DeserializeObject<T>(string Xml){XmlSerializer serializer = new XmlSerializer(typeof(T));StringReader stringReader = new StringReader(Xml);T deserializedData = (T)serializer.Deserialize(stringReader);stringReader.Dispose();return deserializedData;}/// <summary>/// 反序列化为MesProcessData/// </summary>/// <param name="Xml"></param>/// <returns></returns>public static MesProcessData DeserializeXml(string Xml){XmlDocument xmlDoc = new XmlDocument();xmlDoc.LoadXml(Xml);MesProcessData data = new MesProcessData();data = TraverseNodes(xmlDoc.DocumentElement);return data;}static MesProcessData TraverseNodes(XmlNode node){MesProcessData data1 = new MesProcessData();data1.MesName = node.Name;if (node.HasChildNodes){if (node.FirstChild.NodeType == XmlNodeType.Text){data1.MesValue = node.InnerText;return data1;}List<object> datas = new List<object>();foreach (XmlNode childNode in node.ChildNodes){datas.Add(TraverseNodes(childNode));}data1.MesValue = datas.ToArray();}else{data1.MesValue = node.InnerText;}return data1;}private static readonly object Lock = new object();/// <summary>/// 将传入的Object对象序列化为XML格式/// </summary>/// <param name="obj"></param>/// <returns></returns>public static string SerializeToXml(object obj){try{lock (Lock){StringWriter stringWriter = new StringWriter();using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter)){//添加输入对象的头,xmlWriter.WriteStartDocument();FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);foreach (FieldInfo field in fields){object fieldValue = field.GetValue(obj);string fieldName = field.Name;if (fieldValue != null){Type valueType = fieldValue.GetType();if (valueType.IsPrimitive || valueType == typeof(string) || !valueType.IsArray){if (field.Name.Contains("MesValue")){xmlWriter.WriteValue(fieldValue);}else if (field.Name.Contains("MesName")){xmlWriter.WriteStartElement(fieldValue.ToString());continue;}else{xmlWriter.WriteStartElement(field.FieldType.Name.ToString());xmlWriter.WriteValue(fieldValue);xmlWriter.WriteEndElement();continue;}xmlWriter.WriteEndElement();}else if (valueType.IsArray){Array array = (Array)fieldValue;foreach (object item in array){if (item != null){string subXml = SerializeToXml(item);xmlWriter.WriteRaw(subXml);}}}else{string subXml = SerializeToXml(fieldValue);xmlWriter.WriteRaw(subXml);string xml = xmlWriter.ToString();}}}//xmlWriter.WriteEndElement();xmlWriter.WriteEndDocument();}return stringWriter.ToString();}}catch (Exception ex){MesLog.Error("序列化XML失败:" + ex.ToString());return "";}}private static XElement RecursiveProcess(XElement element){List<XElement> newChildren = new List<XElement>();foreach (XElement child in element.Elements()){XElement name = child.Element("MesName");XElement value = child.Element("MesValue");if (name != null && value != null){XElement newElement;if (value.HasElements){// 如果Value有子元素,递归处理XElement processedValue = RecursiveProcess(value);newElement = new XElement(name.Value, processedValue.Nodes());}else{newElement = new XElement(name.Value, value.Value);}newChildren.Add(newElement);}else{if (child.Nodes().Count() > 1){// 如果没有Name和Value,继续递归处理子元素XElement recursivelyProcessedChild = RecursiveProcess(child);newChildren.Add(recursivelyProcessedChild);}else{newChildren.Add(child);}}}element.RemoveAll();element.Add(newChildren);return element;}}}
4.结论
这种方式限定了数据的规则,但是核心原理是一致的。在序列化中,对于可读序列化而言,只有值和数组值的区分。所以我们在控制Object类型序列化时也是参考这个方式,判断是否为数组即可,如果数据格式跟我的不一样的话,那么可以使用反射的形式。例如在一个类中有部分字段为Object类型,那么我们使用反射的形式,将json映射Object中,同样我们也需要判断Json中的Object是否为数组,不是可以直接赋值,是的话则需要递归转换再赋值。将字段中的Object转换为Json也是同理,判断是否为数组,不是则直接转换,是则递归转换。
相关文章:
C#Object类型的索引,序列化和反序列化
前言 最近在编写一篇关于标准Mes接口框架的文章。其中有一个非常需要考究的内容时如果实现数据灵活和可使用性强。因为考虑数据灵活性,所以我一开始选取了Object类型作为数据类型,Object作为数据Value字段,String作为数据Key字段,…...
Unity3D项目开发中的资源加密详解
前言 在Unity3D游戏开发中,保护游戏资源不被非法获取和篡改是至关重要的一环。资源加密作为一种有效的技术手段,可以帮助开发者维护游戏的知识产权和安全性。本文将详细介绍Unity3D项目中如何进行资源加密,并提供相应的技术详解和代码实现。…...

微调Qwen2:7B模型,加入未知信息语料
对于QWen2这样的模型,在微调的时候,语料的投喂格式满足ChatML这样的格式!!! OpenAI - ChatML: 下面是ChatML格式的介绍: https://github.com/openai/openai-python/blob/release-v0.28.0/chatml.mdhttps://github.com/openai/openai-python/blob/release-v0.28.0/chat…...

【Ubuntu】安装SSH启用远程连接
【Ubuntu】安装OpenSSH启用远程连接 零、安装软件 使用如下代码安装OpenSSH服务端: sudo apt install openssh-server壹、启动服务 使用如下代码启动OpenSSH服务端: sudo systemctl start ssh贰、配置SSH(可跳过) 配置文件 …...

【理论】测试开发工程师进阶路线
一、腾讯与阿里的质量保证服务参考 阿里云效测试能力与架构 腾讯 WeTest 测试能力全景图 二、测试开发技术体系 1.用户端测试: Web/App 测试 Web/App 自动化测试 用户端专项测试 用户端安全测试 2.服务端测试: 接口协议与 Mock 接口自动化测试 服务端…...

【BQ3568HM开发板】如何在OpenHarmony上通过校园网的上网认证
引言 前面已经对BQ3568HM开发板进行了初步测试,后面我要实现MQTT的工作,但是遇到一个问题,就是开发板无法通过校园网的认证操作。未认证的话会,学校使用的深澜软件系统会屏蔽所有除了认证用的流量。好在我们学校使用的认证系统和…...
動態住宅IP提升網站訪問成功率
動態住宅IP通常與普通家庭用戶的網路連接相關聯。這種IP地址的特點在於,它是動態變化的,用戶在每次連接時可能會獲得不同的IP地址。這與靜態IP形成了鮮明對比,後者在連接期間保持不變。傳統上,IP地址分為住宅IP和數據中心IP兩類。…...

2024年博客之星主题创作|2024年蓝桥杯与数学建模年度总结与心得
引言 2024年,我在蓝桥杯编程竞赛和数学建模竞赛中投入了大量时间和精力,这两项活动不仅加深了我对算法、数据结构、数学建模方法的理解,还提升了我的解决实际问题的能力。从蓝桥杯的算法挑战到数学建模的复杂应用,我在这些竞赛中…...

Spring Boot/MVC
一、Spring Boot的创建 1.Spring Boot简化Spring程序的开发,使用注解和配置的方式开发 springboot内置了tomact服务器 tomact:web服务器,默认端口号8080,所以访问程序使用8080 src/main/java:Java源代码 src/main/resource:静态资源或配置文件,存放前端代码(js,css,html) s…...
由于请求的竞态问题,前端仔喜提了一个bug
在平常的开发过程中,你可能会遇到这样一个bug。 测试:我在测一个输入框搜索的功能时,告诉你通过输入框输入的内容,和最终通过输入内容搜索出来的结果对不上。 前端:我是通过调用后端接口拿到的数据,这明显…...
【Day25 LeetCode】贪心Ⅲ
一、贪心Ⅲ 1、加油站 134 这道题直接想法是采用二重循环暴力搜索,简单粗暴但是会超时,是因为以每个点为起点最坏的情况可能都要遍历完全部的序列,有大量重复的操作,那有没有优化的地方呢?有一个结论:如果…...

蓝桥杯练习日常|递归-进制转换
未完待续,,,,,, 目录 蓝桥云课760数的计算 一、递归 题目: 我的解题代码: 二、进制转换 任意进制转十进制: 十进制转换为其他进制: 进制蓝桥杯题目…...

AI Agent:深度解析与未来展望
一、AI Agent的前世:从概念到萌芽 (一)早期探索 AI Agent的概念可以追溯到20世纪50年代,早期的AI研究主要集中在简单的规则系统上,这些系统的行为是确定性的,输出由输入决定。随着时间的推移,…...

《SwinIR:使用Swin-Transformer图像恢复》学习笔记
paper:2108.10257 GitHub:GitHub - JingyunLiang/SwinIR: SwinIR: 使用 Swin Transformer 进行图像修复 (官方仓库) 目录 摘要 1、Introduction 2、Related Work 2.1 图像修复 2.2 视觉Transformer…...
如何在Nginx服务器上配置访问静态文件目录并提供文件下载功能
引言 在搭建网站的过程中,我们经常需要让访客通过URL直接访问或下载存储在服务器特定目录下的静态文件。本文将详细介绍如何在Nginx服务器环境中配置一个名为"download"的文件目录,以便用户能够通过浏览器访问并下载其中的手册和其他文档。 …...

ansible自动化运维实战--script、unarchive和shell模块(6)
文章目录 一、script模块1.1、功能1.2、常用参数1.3、举例 二、unarchive模块2.1、功能2.2、常用参数2.3、举例 三、shell模块3.1、功能3.2、常用参数3.3、举例 一、script模块 1.1、功能 Ansible 的 script 模块允许你在远程主机上运行本地的脚本文件,其提供了一…...
理解深度学习pytorch框架中的线性层
文章目录 1. 数学角度: y W x b \displaystyle y W\,x b yWxb示例 2. 编程实现角度: y x W T b \displaystyle y x\,W^T b yxWTb3. 常见错误与易混点解析4. 小结参考链接 在神经网络或机器学习的线性层(Linear Layer / Fully Connect…...

电路研究9.2——合宙Air780EP使用AT指令
这里正式研究AT指令的学习了,之前只是接触的AT指令,这里则是深入分析AT指令了。 软件的开发方式: AT:MCU 做主控,MCU 发 AT 命令给模组的开发方式,模组仅提供标准的 AT 固件, 所有的业务控制逻辑…...
Qt数据库相关操作
目录 一、前言 二、类与接口介绍 1.连接管理类 2.数据操作类 3.数据模型类 4.其它类 三、主要操作流程 1.示例 2.绑定参数 3.事务操作 一、前言 要在Qt中操作数据库,首先要安装对应的数据库,还要确保安装了Qt SQL模块。使用MySQL时࿰…...

2025-01-22 Unity Editor 1 —— MenuItem 入门
文章目录 1 Editor 文件夹2 MenuItem3 使用示例3.1 打开网址3.2 打开文件夹3.3 Menu Toggle3.4 Menu 代码复用3.5 MenuItem 激活与失活4 代码示例 1 Editor 文件夹 Editor 文件夹是 Unity 中的特殊文件夹,Unity 中所有编辑器相关的脚本都需要放置在其中…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...

UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...