C#——XML序列化

2024-09-04 06:28
文章标签 c# xml 序列化 .net netcore

本文主要是介绍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">文件名</paraminternal 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

这篇关于C#——XML序列化的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1135252

相关文章

C#中lock关键字的使用小结

《C#中lock关键字的使用小结》在C#中,lock关键字用于确保当一个线程位于给定实例的代码块中时,其他线程无法访问同一实例的该代码块,下面就来介绍一下lock关键字的使用... 目录使用方式工作原理注意事项示例代码为什么不能lock值类型在C#中,lock关键字用于确保当一个线程位于给定实例的代码块中时

C# $字符串插值的使用

《C#$字符串插值的使用》本文介绍了C#中的字符串插值功能,详细介绍了使用$符号的实现方式,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧... 目录$ 字符使用方式创建内插字符串包含不同的数据类型控制内插表达式的格式控制内插表达式的对齐方式内插表达式中使用转义序列内插表达式中使用

C#中的Converter的具体应用

《C#中的Converter的具体应用》C#中的Converter提供了一种灵活的类型转换机制,本文详细介绍了Converter的基本概念、使用场景,具有一定的参考价值,感兴趣的可以了解一下... 目录Converter的基本概念1. Converter委托2. 使用场景布尔型转换示例示例1:简单的字符串到

C#监听txt文档获取新数据方式

《C#监听txt文档获取新数据方式》文章介绍通过监听txt文件获取最新数据,并实现开机自启动、禁用窗口关闭按钮、阻止Ctrl+C中断及防止程序退出等功能,代码整合于主函数中,供参考学习... 目录前言一、监听txt文档增加数据二、其他功能1. 设置开机自启动2. 禁止控制台窗口关闭按钮3. 阻止Ctrl +

C#解析JSON数据全攻略指南

《C#解析JSON数据全攻略指南》这篇文章主要为大家详细介绍了使用C#解析JSON数据全攻略指南,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、为什么jsON是C#开发必修课?二、四步搞定网络JSON数据1. 获取数据 - HttpClient最佳实践2. 动态解析 - 快速

Olingo分析和实践之EDM 辅助序列化器详解(最佳实践)

《Olingo分析和实践之EDM辅助序列化器详解(最佳实践)》EDM辅助序列化器是ApacheOlingoOData框架中无需完整EDM模型的智能序列化工具,通过运行时类型推断实现灵活数据转换,适用... 目录概念与定义什么是 EDM 辅助序列化器?核心概念设计目标核心特点1. EDM 信息可选2. 智能类

SpringSecurity整合redission序列化问题小结(最新整理)

《SpringSecurity整合redission序列化问题小结(最新整理)》文章详解SpringSecurity整合Redisson时的序列化问题,指出需排除官方Jackson依赖,通过自定义反序... 目录1. 前言2. Redission配置2.1 RedissonProperties2.2 Red

C#连接SQL server数据库命令的基本步骤

《C#连接SQLserver数据库命令的基本步骤》文章讲解了连接SQLServer数据库的步骤,包括引入命名空间、构建连接字符串、使用SqlConnection和SqlCommand执行SQL操作,... 目录建议配合使用:如何下载和安装SQL server数据库-CSDN博客1. 引入必要的命名空间2.

C#读写文本文件的多种方式详解

《C#读写文本文件的多种方式详解》这篇文章主要为大家详细介绍了C#中各种常用的文件读写方式,包括文本文件,二进制文件、CSV文件、JSON文件等,有需要的小伙伴可以参考一下... 目录一、文本文件读写1. 使用 File 类的静态方法2. 使用 StreamReader 和 StreamWriter二、二进

C#中Guid类使用小结

《C#中Guid类使用小结》本文主要介绍了C#中Guid类用于生成和操作128位的唯一标识符,用于数据库主键及分布式系统,支持通过NewGuid、Parse等方法生成,感兴趣的可以了解一下... 目录前言一、什么是 Guid二、生成 Guid1. 使用 Guid.NewGuid() 方法2. 从字符串创建