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 中所有编辑器相关的脚本都需要放置在其中…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...
Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...
