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#比较两个List集合内容是否相同的几种方法

《C#比较两个List集合内容是否相同的几种方法》本文详细介绍了在C#中比较两个List集合内容是否相同的方法,包括非自定义类和自定义类的元素比较,对于非自定义类,可以使用SequenceEqual、... 目录 一、非自定义类的元素比较1. 使用 SequenceEqual 方法(顺序和内容都相等)2.

C#使用DeepSeek API实现自然语言处理,文本分类和情感分析

《C#使用DeepSeekAPI实现自然语言处理,文本分类和情感分析》在C#中使用DeepSeekAPI可以实现多种功能,例如自然语言处理、文本分类、情感分析等,本文主要为大家介绍了具体实现步骤,... 目录准备工作文本生成文本分类问答系统代码生成翻译功能文本摘要文本校对图像描述生成总结在C#中使用Deep

C#从XmlDocument提取完整字符串的方法

《C#从XmlDocument提取完整字符串的方法》文章介绍了两种生成格式化XML字符串的方法,方法一使用`XmlDocument`的`OuterXml`属性,但输出的XML字符串不带格式,可读性差,... 方法1:通过XMLDocument的OuterXml属性,见XmlDocument类该方法获得的xm

C#多线程编程中导致死锁的常见陷阱和避免方法

《C#多线程编程中导致死锁的常见陷阱和避免方法》在C#多线程编程中,死锁(Deadlock)是一种常见的、令人头疼的错误,死锁通常发生在多个线程试图获取多个资源的锁时,导致相互等待对方释放资源,最终形... 目录引言1. 什么是死锁?死锁的典型条件:2. 导致死锁的常见原因2.1 锁的顺序问题错误示例:不同

C#提取PDF表单数据的实现流程

《C#提取PDF表单数据的实现流程》PDF表单是一种常见的数据收集工具,广泛应用于调查问卷、业务合同等场景,凭借出色的跨平台兼容性和标准化特点,PDF表单在各行各业中得到了广泛应用,本文将探讨如何使用... 目录引言使用工具C# 提取多个PDF表单域的数据C# 提取特定PDF表单域的数据引言PDF表单是一

C#实现添加/替换/提取或删除Excel中的图片

《C#实现添加/替换/提取或删除Excel中的图片》在Excel中插入与数据相关的图片,能将关键数据或信息以更直观的方式呈现出来,使文档更加美观,下面我们来看看如何在C#中实现添加/替换/提取或删除E... 在Excandroidel中插入与数据相关的图片,能将关键数据或信息以更直观的方式呈现出来,使文档更

C#实现系统信息监控与获取功能

《C#实现系统信息监控与获取功能》在C#开发的众多应用场景中,获取系统信息以及监控用户操作有着广泛的用途,比如在系统性能优化工具中,需要实时读取CPU、GPU资源信息,本文将详细介绍如何使用C#来实现... 目录前言一、C# 监控键盘1. 原理与实现思路2. 代码实现二、读取 CPU、GPU 资源信息1.

在C#中获取端口号与系统信息的高效实践

《在C#中获取端口号与系统信息的高效实践》在现代软件开发中,尤其是系统管理、运维、监控和性能优化等场景中,了解计算机硬件和网络的状态至关重要,C#作为一种广泛应用的编程语言,提供了丰富的API来帮助开... 目录引言1. 获取端口号信息1.1 获取活动的 TCP 和 UDP 连接说明:应用场景:2. 获取硬

C#使用HttpClient进行Post请求出现超时问题的解决及优化

《C#使用HttpClient进行Post请求出现超时问题的解决及优化》最近我的控制台程序发现有时候总是出现请求超时等问题,通常好几分钟最多只有3-4个请求,在使用apipost发现并发10个5分钟也... 目录优化结论单例HttpClient连接池耗尽和并发并发异步最终优化后优化结论我直接上优化结论吧,

C#使用yield关键字实现提升迭代性能与效率

《C#使用yield关键字实现提升迭代性能与效率》yield关键字在C#中简化了数据迭代的方式,实现了按需生成数据,自动维护迭代状态,本文主要来聊聊如何使用yield关键字实现提升迭代性能与效率,感兴... 目录前言传统迭代和yield迭代方式对比yield延迟加载按需获取数据yield break显式示迭