C#Object类型的索引,序列化和反序列化

news2025/1/24 20:58:34

前言

最近在编写一篇关于标准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 字符串为 JObject
            JObject 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);
                }
                else
                    datas.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也是同理,判断是否为数组,不是则直接转换,是则递归转换。

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

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

相关文章

头像生成小程序搭建(免费分享)

如下图为小程序页面的基本效果&#xff0c;下面将介绍该小程序的功能 页面template代码如下&#xff1a; <template><view class"avatar-containner"><block v-if"!showCropper"><image class"pageback" src"../../s…

Unity自学之旅05

Unity自学之旅05 Unity学习之旅⑤&#x1f4dd; AI基础与敌人行为&#x1f94a; AI导航理论知识&#xff08;基础&#xff09;开始实践 &#x1f383; 敌人游戏机制追踪玩家攻击玩家子弹碰撞完善游戏失败条件 &#x1f917; 总结归纳 Unity学习之旅⑤ &#x1f4dd; AI基础与敌…

【分布式日志篇】从工具选型到实战部署:全面解析日志采集与管理路径

网罗开发 &#xff08;小红书、快手、视频号同名&#xff09; 大家好&#xff0c;我是 展菲&#xff0c;目前在上市企业从事人工智能项目研发管理工作&#xff0c;平时热衷于分享各种编程领域的软硬技能知识以及前沿技术&#xff0c;包括iOS、前端、Harmony OS、Java、Python等…

电子应用设计方案102:智能家庭AI鱼缸系统设计

智能家庭 AI 鱼缸系统设计 一、引言 智能家庭 AI 鱼缸系统旨在为鱼类提供一个健康、舒适的生活环境&#xff0c;同时为用户提供便捷的管理和观赏体验。 二、系统概述 1. 系统目标 - 自动维持水质稳定&#xff0c;包括水温、酸碱度、硬度和溶氧量等关键指标。 - 智能投食&…

【安当产品应用案例100集】034-安当KSP支持密评中存储数据的机密性和完整性

安当KSP是一套获得国密证书的专业的密钥管理系统。KSP的系统功能扩展图示如下&#xff1a; 我们知道商用密码应用安全性评估中&#xff0c;需要确保存储的数据不被篡改、删除或者破坏&#xff0c;必须采用合适的安全方案来确保存储数据的机密性和完整性。KSP能否满足这个需求呢…

linux系统下的磁盘扩容

背景&#xff1a;之前通过虚拟机装linux时硬盘空间设置的不够用&#xff0c;所以需要再加点容量。 1、首先通过虚拟机来扩展硬盘 注意&#xff1a;需要关闭linux系统&#xff1b;需要删除之前的快照&#xff1b; 我原来为27G&#xff0c;现在增加到了40G&#xff0c;如下图: …

【MySQL】 库的操作

欢迎拜访&#xff1a;雾里看山-CSDN博客 本篇主题&#xff1a;【MySQL】 库的操作 发布时间&#xff1a;2025.1.23 隶属专栏&#xff1a;MySQL 目录 库的创建语法使用 编码规则认识编码集查看数据库默认的编码集和校验集查看数据库支持的编码集和校验集指定编码创建数据库验证不…

fpga学习入门 串口rs232回环

奇偶检验位这里是省略了 做好回环后可以使用上位机做回环测试&#xff0c;top文件写的方式就是将rx&#xff08;fpga端&#xff09;接受到的模块&#xff08;pc端&#xff09;tx发送出去&#xff0c;这两个端口用杜邦线连接&#xff0c;同理模块的rx连接fpga的tx&#xff0c;…

认识Django项目模版文件——Django学习日志(二)

1.默认文件介绍 └── djangoproject1/├── djangoproject1/│ ├── urls.py [URL和函数的对应关系]【常用文件】│ ├── settings.py [项目配置文件]【常用文件】│ ├── _init_.py│ ├── wsgi.py [接受网络请求] 【不要动】│ └──…

微信小程序中常见的 跳转方式 及其特点的表格总结(wx.navigateTo 适合需要返回上一页的场景)

文章目录 详细说明总结wx.navigateTo 的特点为什么 wx.navigateTo 最常用&#xff1f;其他跳转方式的使用频率总结 以下是微信小程序中常见的跳转方式及其特点的表格总结&#xff1a; 跳转方式API 方法特点适用场景wx.navigateTowx.navigateTo({ url: 路径 })保留当前页面&…

postgresql15的启动

PostgreSQL是一个功能非常强大的、源代码开放的客户/服务器关系型数据库管理系统&#xff0c;且因为许可证的灵活&#xff0c;任何人都可以以任何目的免费使用、修改和分发PostgreSQL。现在国产数据库大力发展阶段&#xff0c;学习和熟悉postgresql的功能是非常有必要的&#x…

ChatGPT结合Excel辅助学术数据分析详细步骤分享!

目录 一.Excel在学术论文中的作用✔ 二.Excel的提示词✔ 三. 编写 Excel 命令 四. 编写宏 五. 执行复杂的任务 六. 将 ChatGPT 变成有用的 Excel 助手 一.Excel在学术论文中的作用✔ Excel作为一种广泛使用的电子表格软件&#xff0c;在学术论文中可以发挥多种重要作用&a…

大模型 / 智能体在智能运维领域的应用总结与发展趋势概述

智能体 智能运维 &#xff1f; 回顾大模型的发展 大模型的发展在过去两年间呈现出爆炸式的增长&#xff0c;成为推动人工智能领域快速进步的关键力量。 2023年3月&#xff1a;百度发布了其知识增强的大语言模型产品“文心一言”&#xff0c;这标志着国内AI大模型产业竞争的…

戴尔电脑设置u盘启动_戴尔电脑设置u盘启动多种方法

最近有很多网友问&#xff0c;戴尔台式机怎么设置u盘启动&#xff0c;特别是近两年的戴尔台式机比较复杂&#xff0c;有些网友不知道怎么设置&#xff0c;其实设置u盘启动有两种方法&#xff0c;下面小编教大家戴尔电脑设置u盘启动方法。 戴尔电脑设置u盘启动方法一、戴尔进入b…

【博客之星】年度总结:在云影与墨香中探寻成长的足迹

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、年度回顾 1、创作历程 2、个人成长 3、个人生活与博客事业 二、技术总结 1、赛道选择 2、技术工具 3、实战项目 三、前景与展望 1、云原生未来…

《安富莱嵌入式周报》第349期:VSCode正式支持Matlab调试,DIY录音室级麦克风,开源流体吊坠,物联网在军工领域的应用,Unicode字符压缩解压

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 视频版&#xff1a; 《安富莱嵌入式周报》第349期&#xff1a;VSCode正式支持Matlab调试&#xff0c;DIY录音室级麦克风…

cursor ide配置远程ssh qt c++开发环境过程记录

cursor是啥就不介绍了&#xff0c;好像是目前最好用的ai ide&#xff0c;下面主要是配置远程ssh连接linux机器进行qt5 c程序运行的配置过程记录。 一、c_cpp_properties.json 在项目根目录的.vscode目录里面新建c_cpp_properties.json文件&#xff0c;根据你的实际情况配置该文…

Langchain+文心一言调用

import osfrom langchain_community.llms import QianfanLLMEndpointos.environ["QIANFAN_AK"] "" os.environ["QIANFAN_SK"] ""llm_wenxin QianfanLLMEndpoint()res llm_wenxin.invoke("中国国庆日是哪一天?") print(…

lwIP——3 内存管理

目录 1.什么是内存管理 2.lwIP内存堆 3.lwIP内存堆程序代码解析 3.1 mem_init程序解析 3.2 mem_malloc程序解析 3.3 mem_free程序解析 4.lwIP内存池 5.lwIP内存池程序代码解析 5.1 实现lwIP内存池的文件 5.1.1 memp_priv.h 5.1.2 memp_std.h 5.1.3 memp.h memp_t 枚…

使用 Serilog 在 .NET Core 6.0 中日志记录

在本文中&#xff0c;我们将讨论日志记录的基础知识以及在 .NET Core 6 中使用 Serilog 的逐步实现。 先决条件 1、Visual Studio 2022。 2、C# 和 .NET Core 的基础知识。 3、.NET Core 6 SDK。 日志记录基础知识 从技术角度来说&#xff0c;日志记录是记录事件并捕获应用程…