C# .NET 中的序列化 II - XML 序列化






2.83/5 (6投票s)
解释 XML 序列化、架构,并提供一个 XML 序列化的示例。
摘要
在 C# .NET 中,序列化在各种功能(如远程处理)中扮演着关键角色。开发人员可能经常需要执行自定义序列化,以便完全控制序列化和反序列化过程。二进制 .NET 序列化过程可能不足以在一个平台上反序列化另一个平台序列化的输出。在本系列的第二篇文章中,Anupam Banerji 解释了 XML 序列化、架构,并提供了一个 XML 序列化的示例。
引言
XML 序列化是一种以可移植、人类可读的格式存储对象状态的方法。XML 序列化的对象可以被任何平台反序列化,而不仅仅是 .NET 平台(这是 .NET 二进制格式序列化对象所要求的)。XML 序列化还可以使用 XML 架构进行标准化。这使得跨多个操作系统、平台或有多个开发方的业务流程能够进行序列化。
与二进制序列化相比,XML 序列化有几个缺点。序列化的是对象本身,而不是整个对象图。另一个缺点是只能序列化公共字段。因此,在对象设计时需要仔细考虑 XML 序列化。XML 序列化的优势应该是将 XML 序列化集成到对象设计和实现中的决定性因素。
(反)序列化一个对象
序列化通过实例化一个 XmlSerializer 对象来执行。序列化的输出被写入一个底层流对象。这与二进制序列化中使用的过程相同。反序列化的对象应强制转换为原始数据类型(反序列化时返回一个通用的 object 类型)。
以下代码序列化一个 double 类型
using System.Xml.Serialization; using System.IO; XmlSerializer xs = new XmlSerializer(typeof(double)); FileStream fs = new FileStream(, FileMode.Create); xs.Serialize(fs, (double)(10)); fs.Close();
该文件包含 XML 输出,对象状态在一个节点中
<?xml version="1.0"?>
<double>10</double>
要将对象反序列化回原始数据类型(注意强制类型转换)
double d = (double)xs.Deserialize(fs);
使用 XML 序列化器的一个缺点是,它只将一个对象状态写入输出,而不是多个对象状态。这与二进制序列化器类似。我并不完全同意微软®对 Serialize() 方法的实现;序列化大量对象需要大量文件。另一个问题是,即使多个对象状态被写入单个文件,也无法在不将正确对象的内容读入底层流的情况下实现对象的反序列化。
类也可以被序列化。该类和被序列化的成员必须标记为 public。该类还必须有一个无参数的构造函数;这个构造函数可以被重载。与二进制序列化不同,[Serializable] 属性不必应用于该类。私有和受保护的成员会被忽略,任何继承的字段也不会被序列化。
(反)序列化一个 DataSet
DataSet 对象也可以使用 XmlSerializer 对象进行(反)序列化。有两种方法可以实现这一点。
开发者可以选择在实例化并填充 DataSet 对象后实现(反)序列化对象的方法。第二种方法是使用 DataSet 的方法。
以下代码展示了如何使用 DataSet 的方法序列化一个 DataSet 实例
using System.Data; FileStream fs = new FileStream(<file name>, FileMode.Create); DataSet ds = new DataSet(); // Populate DataSet object ds.WriteXml(fs);
如果我实现 XmlSerializer 方法,序列化后的文件看起来是这样的
<?xml version="1.0" encoding="utf-8"?>
<DataSet>
<xs:schema id="NewDataSet"
xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
...
<diffgr:diffgram
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1" />
</DataSet>
如果我实现实例化的 DataSet 方法,我会得到这个输出
<NewDataSet />
第二个输出文件中没有数据。因此,我建议使用 XmlSerializer 对象,直到 DataSet 实例化方法的缺陷得到解决。
控制序列化过程
在大型组织中,不同平台之间实现的流程可能需要通用标准。一个例子是,一个 *NIX 可执行文件使用 .NET 可执行文件的序列化输出来执行任务。*NIX 可执行文件可能要求 XML 输出符合特定格式,即架构(schema)。我们稍后会讨论 XML 架构。
如果没有实现自定义控制,XML 序列化器会将序列化对象的所有成员作为 XML 元素输出。开发者可以通过使用序列化属性标记字段来控制 XML 输出。例如,用 [XmlAttribute] 标记一个字段会使该字段作为属性存储,而不是元素。还有一些更重要的属性:[XmlIgnore] 会忽略被标记的公共字段,[XmlElement] 将字段存储为元素(这是默认过程),而 [XmlArray] 将字段存储为复杂对象的数组,例如,一个用户定义数据类型的字段。
开发者也可以通过实现 IXmlSerializable 接口来完全控制 XML 的(反)序列化过程。该接口包含 GetSchema()、ReadXml() 和 WriteXml() 方法。开发者可以从头开始读写 XML 输出,并可以实现一个经批准的架构,以确保序列化按标准规范执行。
使用 XML 架构
XML 架构本质上是包含特定存储格式信息的模板文件。XML 架构允许 .NET 应用程序将标准输出(反)序列化到 XML 文件。XML 架构可以包含所有格式信息,也可以包含对文档类型定义(DTD)文件的引用。创建 XML 架构定义(XSD)文件超出了本文的范围。
架构文件使用 XML 架构定义工具 (Xsd.exe) 集成到 Visual Studio® 项目中。打开 Visual Studio 命令提示符并输入
xsd <file name> /classes /language:CS
XSD 创建一个 C# 类,该类在(反)序列化时符合该架构。在编写任何方法之前,应在 XML 架构中设计好类的字段和属性。下图显示了符合 XSD 规范的类的开发顺序。
图 1:带有 XSD 规范的类开发流程图。
开发者可以使用开源工具来创建和修改 XSD。IXmlSerializable 接口中的 GetSchema() 方法也允许开发者动态创建架构。当多个类需要相同的架构实现时,继承一个实现了此架构的基类是最佳实践。
一个简单示例:可 XML 序列化的类
我们编写一个不符合规范的 XML 类,它由 XmlSerializer 对象进行(反)序列化
public class XmlClass { public double field { get; set; } // Parameterless constructor for XML private XmlClass() { } // Overloaded constructor public XmlClass(double initialValue) { field = initialValue; } }
XML 序列化不需要属性来进行序列化。我们只需要实现一个无参数的构造函数。私有成员不会被序列化,需要通过实现 IXmlSerializable 接口来单独存储。
要序列化该类的实例,我们使用一个 TextWriter 对象
XmlSerializer xs = new XmlSerializer(typeof(XmlClass)); TextWriter tw = File.CreateText(<file name>); XmlClass xc = new XmlClass(10); xs.Serialize(tw, xc); tw.Close();
我们打开包含序列化输出的文本文件,可以看到被序列化的公共字段有一个存储的值
<?xml version="1.0" encoding="utf-8"?>
<XmlClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<field>10</field>
</XmlClass>
要反序列化,创建一个 TextReader 对象的实例,并将反序列化的输出强制转换为 XmlClass 对象
TextReader tr = File.OpenText(); XmlClass xcd = (XmlClass)xs.Deserialize(tr); tw.Close(); Console.WriteLine(xcd.field.ToString());
结论
XML 序列化提供了一套简单而高效的技术,用于在多个软件平台之间传输对象状态。开发者可以通过实现 IXmlSerializable 接口来完全控制(反)序列化过程。序列化也可以通过属性或遵循 XSD 格式进行自定义。因此,应考虑将实现 XML 序列化框架作为二进制序列化的替代方案的好处。
这是本系列的第二篇文章。
要下载本文的 PDF 格式,请访问 Coactum Solutions:http://www.coactumsolutions.com/Articles.aspx。