26.5.3 XML序列化
XML序列化是将对象的公共属性和字段转换为XML格式,以便存储或传输的过程。反序列化则是从XML输出中重新创建原始状态的对象。XML序列化中最主要的类是XmlSerializer类,它的最重要的方法是Serialize和Deserialize方法,它位于System.Xml.Serialization命名空间。
使用XmlSerializer序列化类时的一些注意事项如下:
❑要序列化的类必须有默认构造函数,才能使用XmlSerializer序列化;
❑方法不能被序列化;
❑索引器、私有字段或只读属性(只读集合属性除外)不能被序列化。
代码清单26-12 演示了XmlSerializer类的用法。这里特别需要说明的是第一点,代码清单26-8中的默认构造函数是必需的,因为反序列化本质上使用的是反射,需要默认构造函数来实例化类,如果去掉其中的默认构造函数,则编译没有问题,再运行就会报错:
未经处理的异常:System.InvalidOperationException:ProgrammingCSharp4.Person无法序列化,因为它没有无参数的构造函数。
代码清单26-12 使用XmlSerializer进行序列化和反序列化
using System;
using System.Collections;
using System.IO;
using System.Text;
using System.Xml.Serialization;
namespace ProgrammingCSharp4
{
class SerializeSample
{
//序列化后生成的文件
string strFile="person.xml";
public static void Main(string[]args)
{
ArrayList favourites=new ArrayList();
favourites.Add(“看电视”);
favourites.Add(“看电影”);
favourites.Add(“上网冲浪”);
Person person=new Person(favourites){height="175cm",birthday="2000-1-1"};
person.SetWeight(80.00);
Console.WriteLine(person.ToString());
SerializeSample ss=new SerializeSample();
ss.Serialize(person);
Person person2=ss.DeSerialize();
Console.WriteLine(person2.ToString());
}
//序列化
public void Serialize(Person person)
{
using(FileStream fs=new FileStream(strFile,FileMode.Create))
{
XmlSerializer formatter=new XmlSerializer(typeof(Person));
formatter.Serialize(fs,person);
}
}
//反序列化
public Person DeSerialize()
{
Person person;
using(FileStream fs=new FileStream(strFile,FileMode.Open))
{
XmlSerializer formatter=new XmlSerializer(typeof(Person));
//Deserialize方法返回object类型,因此需要显示类型转换
person=(Person)formatter.Deserialize(fs);
}
return person;
}
}
}
运行结果为:
Name:张三
Height:175cm
Birthday:2000-1-1
Weight:80
Favourites:看电视
看电影
上网冲浪
Name:张三
Height:175cm
Birthday:2000-1-1
Weight:0
Favourites:看电视
看电影
上网冲浪
请按任意键继续……
生成的xml文件内容为:
<?xml version="1.0"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<height>175cm</height>
<birthday>2000-1-1</birthday>
<Favourites>
<anyType xsi:type="xsd:string">看电视</anyType>
<anyType xsi:type="xsd:string">看电影</anyType>
<anyType xsi:type="xsd:string">上网冲浪</anyType>
</Favourites>
</Person>
图26-12说明了上述过程。
图 26-12 使用xml格式序列化
在这里我们回答前文提出的两个问题中的第一个,请注意观察序列化后生成的xml文档内容,存在的元素如下:
❑height
❑birthday
❑Favourites集合(只读)
下列元素并未被序列化:
❑私有字段:Name和Weight
❑只读属性:Name
❑方法:SetWeight和ToString
可见,之所以区分出这么多种类型的成员,是为了让大家认识到哪些类型的成员参与序列化,哪些不参与。
我们继续回答第二个问题:为什么在代码清单26-8中加入一个自定义的构造函数:
public Person(ArrayList favourites)
{
this.favourites=favourites;
}
原因如下:
❑Favourites是只读属性,因此需要在Person类实例化时就初始化favourites列表的内容。
❑不能放在默认构造函数初始化,那会导致在反序列化时对favourites列表初始化两次:默认构造函数中执行一次;反序列化时从xml文档读取再执行一次。