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

C#——XML序列化

开发环境

VS2022

.net core 6.0

序列化概念

序列化是将内存中的对象或者对象图(一组相互引用的对象)拉平为一个可以保存或进行传输的字节流,或者XML节点。反序列化正好相反,它把数据流重新构造成内存中的一个对象或者对象图。

序列化用途

序列化和反序列化通常用于:

· 通过网络或程序边界传输对象

· 在文件或者数据库中保存对象

此外,它还可以用于深度克隆对象。而数据契约和XML序列化引擎也可以当作通用工具,用于加载和保存已知结构的XML文件。

可序列化的项

  • 公共类的公共读/写属性和字段。

  • 执行 ICollection 或 IEnumerable 的类 。

  • XmlElement 对象。

  • XmlNode 对象。

  • DataSet 对象。

序列化常用特性

XmlRoot——申明根结点,如: [XmlRoot(ElementName = "Root")]

XmlIgnore——忽悠某个属性或字段,如 :[XmlIgnore] public int Id;

XmlInclude——是否包含某个类,如:[XmlInclude(typeof(Results))]

XmlArray——申明集合

XmlArrayItem——申明集合中元素,如下:

        [XmlArray("Targets", Namespace = "TwoPoint")]
        [XmlArrayItem("Target", Namespace = "TwoPoint")]
        public Point[] Points { get; set; }

XML 序列化注意事项

使用 XmlSerializer 类时,应注意以下事项:

  • 序列化数据只包含数据本身和类的结构。 

  • 只能序列化公共属性和字段。 属性必须具有公共访问器(get 和 set 方法)。 

  • 类必须具有无参数构造函数才能被 XmlSerializer 序列化。

  • 方法不能被序列化。

  • 如下所述,如果实现 IEnumerable 或 ICollection 的类满足某些要求,XmlSerializer 则可以处理这些类 。

    实现 IEnumerable 的类必须实现采用单个参数的公共 Add 方法 。

    实现 ICollection 的类(如 CollectionBase)必须具有采用整型的公共“Item”索引属性(在 C# 中为索引器),而且它必须有一个“integer”类型的公共“Count”属性 。 传递给 Add 方法的参数必须与从“Item”属性返回的类型相同,或者为此类型的基之一 。

常见错误及解决办法

以下为愚初次使用时遇到的一引问题,及解决办法:

 不同命名空间下的相同类名下异常

InvalidOperationException: Types 'WpfApp.Xml.Results.Target' and 'WpfApp.Xml.PlanInfo.Target' both use the XML type name, 'Target', from namespace ''. Use XML attributes to specify a unique XML name and/or namespace for the type.

解决办法:如上黄色字体,即为序列化的对象添加Namespace,如下

    [XmlType(Namespace = "WpfApp.Xml.Results")]
    public class Target
    {
        /// <summary>
        /// 编号
        /// </summary>
        [XmlAttributeAttribute(AttributeName = "id")]
        public double NO { get; set; }

    }

注意仅需要添加Namespace即可,不需要添加TypeName。

很多文章提到应该添加TypeName和Namespace,如下的操作方式:

    [XmlType(TypeName = "PTarget", Namespace = "WpfApp.Xml.Info")]
    public class Target
    {
        /// <summary>
        /// 编号
        /// </summary>
        [XmlAttributeAttribute(AttributeName = "id")]
        public double NO { get; set; }

    }

但若添加了TypeName会导致你后一个不同NameSpace下的类改为你Namespace中设置的名称。

非集合属性或字段添加了集合特性

InvalidOperationException: For non-array types, you may use the following attributes: XmlAttribute, XmlText, XmlElement, or XmlAnyElement.

集合属性或字段添加了 XmlElement

集合不能使用它,否则会导致它的子元素全部显示为Targets,而应该如下:

        [XmlArray("Targets")]
        [XmlArrayItem("Target")]
        public Point[] Points { get; set; }

XmlArray指定了集合Points在Xml中的显示名称,

XmlArrayItem指定了集合中元素在Xml中的显示名称。

对象序列化与反序列化常用代码

对象序列化为XML文件

        /// <summary>
        /// 序列化对象为XML文件
        /// </summary>
        internal static void XmlSerializer<T>(string fileName, T t) where T : new()
        {

            try
            {

                XmlSerializer serializer = new(typeof(SerializationWrapper));
                using TextWriter tr = new StreamWriter(fileName, false, Encoding.UTF8);
                // 序列化包装类
                serializer.Serialize(tr, t);
                tr.Close();
                tr.Dispose();
            }
            catch (Exception ex)
            {
                Debug.WriteLine("序列化失败");
                Exception exception = new("序列化失败");
                throw exception;
            }
        }

xml文件反序化为对象

        /// <summary>
        /// 反序列化XML文件为对象
        /// </summary>
        /// <param name="fileName">文件名</param
        internal static T XmlDeserialize<T>(string fileName) where T : new()  
        {
            using FileStream s = File.OpenRead(fileName);

            // 创建包装类的实例并添加对象
            XmlSerializer xs = new(typeof(T));
            T sw = (T)xs.Deserialize(s);
            return sw;
        }

上述代码最好还是添加上try……catch……以进行错误处理。

对象序列化为字符串

        /// <summary>
        /// 将对象序列化为XML字符串
        /// </summary>
        /// <typeparam name="T">需要序列化的类型</typeparam>
        /// <param name="t">序列化的对象实例</param>
        /// <returns>序列化对象的字符串</returns>
        internal static string Object2XmlStringSerializer<T>(T t) where T : new()
        {
            try
            {
                // 创建包装类的实例并添加对象
                T wrapper = t;
                // 创建XmlSerializer的实例,指定根元素名称
                XmlSerializer serializer = new(typeof(T));

                // 使用StringWriter来捕获序列化后的XML内容
                using (StringWriter stringWriter = new())
                {
                    serializer.Serialize(stringWriter, wrapper);
                    string xmlContent = stringWriter.ToString();
                    Debug.WriteLine(xmlContent);
                    return xmlContent;
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("序列化失败");
                Exception exception = new("序列化失败");
                throw exception;
            }
        }

若需要指定编码方式,那么就需要转化为数据流,然后指定相应的编码方式后再读取,如下:

                using (MemoryStream memoryStream = new ())
                {
                    using (StreamWriter streamWriter = new (memoryStream, Encoding.UTF8))
                    {
                        serializer.Serialize(streamWriter, t);
                        streamWriter.Flush();
                        memoryStream.Position = 0;
                        using (StreamReader streamReader = new (memoryStream, Encoding.UTF8))
                        {
                            string xmlContent = streamReader.ReadToEnd();
                            Debug.WriteLine(xmlContent);
                            return xmlContent;
                        }
                    }
                }

其实没有必要指定编码方式,从测试结果来看,反序列化时并不需要指定相应的编码方式,也可以正确进行解码。

xml字符串反序化为对象

/// <summary>
/// 将XML字符串反序列化为对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="xmlString"></param>
/// <returns></returns>
internal static T XmlStringDeserializer<T>(string xmlString) where T : new()
{
    // 使用StringReader包装XML字符串
    using StringReader stringReader = new(xmlString);
    try
    {
        XmlSerializer serializer = new(typeof(T));
        // 反序列化XML字符串
        T root = (T)serializer.Deserialize(stringReader);
        return root;
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

参考资料

《C# 核心技术指南(原书第7版)》

XML 序列化详细信息 - .NET | Microsoft Learn


http://www.kler.cn/news/288726.html

相关文章:

  • 利用通义灵码实现我的第一次开源贡献
  • Web服务如何实现一个视频项目架构
  • RCE漏洞
  • Vue 3 中如何对接高德地图
  • goreplay流量重放备忘
  • sqlite3的db.serialize方法:确保数据库操作串行化的利器
  • Autosar OS基础知识导图
  • 根据xml模板导出excel
  • Gitee镜像关联GitHub仓库
  • 【MySQL-24】万字全面解析<索引>——【介绍&语法&性能分析&使用规则】
  • 数据库:实验六存储过程
  • websocket:两台PC间数据传输
  • Leetcode 146. LRU 缓存(Medium)
  • 【知识库系列】MPR/多模态方向观察:图像视频与3D生成
  • 你的专利真的值钱吗?五重标准检验,让你的创新价值飙升
  • 深度学习:革新药物心脏毒性预测的新篇章
  • 局域网通信时,解决在一些设备上NsdManager发现服务失败的问题
  • 9_3_LineEdit
  • 抓取海外电商平台数据时,是否最好使用当地的IP?
  • 基础闯关4
  • 数学建模常用工具总结
  • 关于Linux(CentOS 7)中的用户sudo命令
  • 知识付费小程序搭建:开启知识变现新时代
  • 采用SIP封装的传感器系列:ARS19510LUBBTN、A19520LUBBTN、A1696PKHTN、A1694PKLN-RNZBE(资料)
  • Learning——protobuf的下载
  • 【Springboot服务实现类】用户登录逻辑梳理(未完待续)
  • 【管理型文档】软件需求管理过程(原件)
  • 使用 ip route 命令配置 Linux 路由表的详细指南
  • AI BT人工智能交互平台应用程序重磅上线,开启全球数字革命
  • 探索 HarmonyOS NEXT Developer Beta6,开启创新应用