天天看点

序列化 序列化的定义 对象图自定义序列化使用特性定制序列化

序列化:描述了持久化一个对象的状态到流的过程。被持久化的数据次序包含所有以后需要用来重建(反序列化)对象状态所必须的信息。

从定义可以看出2点

1.序列化的用途:持久化一个对象

2.序列化的优点:序列化是双向的(序列化与反序列化),因为被序列化的数据包含所有以后用来重新对象状态的信息。

下面我们先来看一个序列化的简单的例子,来说明上述的两点。

上面的示例代码,展示了序列化用户数据与反序列化用户数据的过程。

序列化数据为什么可以进行反序列化(也就是说,为什么反序列化时,数据彼此之间的关系不会出错(is-a(继承的关系);has-a(从属关系))),这就要说到对象图的作用了。

当对象被序列化时,CLR将处理所有相关的对象,一组关联对象被总称为一个对象图。它提供了一种很简明的方式来记载一组对象的引用关系。对象图中的每个对象被赋予一个独有的数值类型的值,这个值可任意地赋给对象图中的成员,以此来记录对象的依赖关系。

序列化 序列化的定义 对象图自定义序列化使用特性定制序列化

上图可知,Order引用了Product,OnlineOrder引用了Order和Product。在CLR中,这种关系表示为:[Order

3,ref 2],[Product 2],[OnlineOrder 1,ref 3,ref

2]。当序列化OnlineOrder时,根据对象图,使Order和Product参与其中。(注意XmlSerializer不使用对象图。) 

大多数情况我们只要采用.NET提供的序列化方式,就可以完成我们的需求。即:

1.需要序列化的类添加[Serializable]特性。注意:该类所关联的所有数据(基类、需要参与序列化的属性)都必须支持序列化

2.选用恰当的序列化格式化程序(BinaryFormatter:二进制流;SoapFormatter:SOAP消息;XmlSerializer:XML文件)

当.NET提供给我们的序列化方式无法满足我们的需求时,就需要使用ISerializable自定义序列化。

例如:被序列化为流的字符串对象必须全是大写字母;从流中反序列化为小写字母。

首先我们来了解一下ISerializable接口

1.ISerializable所属命名空间:

2.ISerializable接口的定义:

从接口的定义可以看出,该接口需要实现一个void

GetObjectData(SerializationInfo info, StreamingContext context);方法。

a.该方法的用途:

序列化格式化程序进行序列化时,会调用该方法。(在该方法中可以对序列化的过程,进行一些干预。)

b.该方法有两个参数:

第一个参数:以键/值对的形式包含了所有参与序列化的数据、以及填充序列化的方法(序列化与反序列化基本就是通过该对象(SerializationInfo)实现。)

第二个参数:包含了序列化流的源的相关信息(一般用不到)

3.实现自定义序列化的类,必须提供一个如下签名的构造函数,以允许运行库引擎设置对象的状态

该构造函数的用途:

序列化格式化程序进行反序列化时,会调用该方法(在该方法中可以对反序列化的过程,进行一些干预。)

4.实现代码

PS:SoapFormatter在System.Runtime.Serialization.Formatters.Soap命名空间下

运行结果:

a.序列化结果

序列化 序列化的定义 对象图自定义序列化使用特性定制序列化

 从红色框可以看出,用户数据被序列化为大写形式

b.反序列化结果

序列化 序列化的定义 对象图自定义序列化使用特性定制序列化

用户数据被反序列化为小写形式

 自.NET2.0发布以来,定制序列化过程的首选方式是定义一些具有新的序列化相关特性的方法(这些特性如[OnSerializing]、[OnSerialized]、[OnDeserializing]、[OnDeserialized])。使用这些特性,减少了实现ISerializable的麻烦,因为不需要手动与输入的SerializationInfo参数交互、二十载格式化程序操作该类型时直接修改状态数据。

下面是我从MSDN上找到的关于序列化特性的介绍。

序列化 序列化的定义 对象图自定义序列化使用特性定制序列化

 我将用红色框标注出的两个特性,来实现之前的ISerializable实现的功能。

还有一点需要注意:当应用这些特性时,必须定义方法接收一个StreamingContext参数并返回空(否则,将受到一个运行时异常。)

实现代码

调用的代码和之前的完全一样,这里就不贴出了。大家可以自己去测试。

感谢大家的阅读