当前位置: 首页 > article >正文

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 字符串为 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.kler.cn/a/525436.html

相关文章:

  • VLLM性能调优
  • 全面解析文件上传下载删除漏洞:风险与应对
  • 16、智能驾驶域控的材料回收
  • 团体程序设计天梯赛-练习集——L1-025 正整数A+B
  • 【PySide6快速入门】QLineEdit 输入框
  • Web 代理、爬行器和爬虫
  • 层次聚类构建层次结构的簇
  • 智能工厂能耗管理:Python助力节能增效
  • 真正的智能与那只蝴蝶
  • 后盾人JS--闭包明明白白
  • 人工智能 - 1
  • 【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.21 索引宗师:布尔索引的七重境界
  • sem_init的概念和使用案例
  • ollama的setup.exe和ollama-windows-amd64.zip区别
  • 网易有道开源 “子曰 - o1” 推理模型
  • Python动量策略实战:大幅跑赢市场的底层逻辑
  • 跑腿小程序/智能派单/系统派单/同城配送/校园跑腿/预约取件/用户端+骑手端【全开源】
  • 多线程进阶(一命通关)
  • 抠图神器,全离线使用,支持win和mac
  • github制作静态网页
  • 高精度算法:高精度减法
  • 【C++动态规划 状态压缩】2597. 美丽子集的数目|2033
  • 单细胞-第五节 多样本数据分析,打分R包AUCell
  • 简单聊聊“DeepSeek”
  • 【设计测试用例自动化测试性能测试 实战篇】
  • 2.3.1 基本数据类型