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 中所有编辑器相关的脚本都需要放置在其中…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...
华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...
【LeetCode】算法详解#6 ---除自身以外数组的乘积
1.题目介绍 给定一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O…...
git: early EOF
macOS报错: Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/ remote: Enumerating objects: 2691797, done. remote: Counting objects: 100% (1760/1760), done. remote: Compressing objects: 100% (636/636…...
《Docker》架构
文章目录 架构模式单机架构应用数据分离架构应用服务器集群架构读写分离/主从分离架构冷热分离架构垂直分库架构微服务架构容器编排架构什么是容器,docker,镜像,k8s 架构模式 单机架构 单机架构其实就是应用服务器和单机服务器都部署在同一…...
