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.5.3 XML序列化 - 图1

图 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文档读取再执行一次。