浅析.NET中的Serialization

** 摘要 ** ** ** 本文简要介绍了 .NET 中的序列化( Serialization )概念,以及在代码中实作 Serialization 的方法。文章的最后介绍了 Serialization 在 Clone 方法中的运用。

** Serialization ** ** 的概念 ** ** **

Serialization 是 .NET 中一种实现对象持久性( Persistent )的机制。它是一个将对象中的数据转换成一个单一元素(通常是 Stream )的过程。它的逆过程是 Deserialization 。 Serialization 的核心概念是将一个对象的所有数据看作一个独立的单元。

一般说来,在两种情况下非常需要 Serialization : 1 )当我们希望能够将对象当前的状态完整地保存到存储介质中,以便我们以后能够精确地还原对象时; 2 )当我们希望将对象从一个应用程序空间( Application domain )传递到另一个应用程序空间时。例如, Windows Form 程序就是利用 Serialization 机制来实现剪贴板的 copy & paste 的。

.NET Framework 支持两种类型的 Serialization : Shallow Serialization 和 Deep Serialization 。

所谓 Shallow Serialization 是将对象的可读写( read-write )属性的值转换成字节流,而对象内部的数据(没有通过 read-write 属性暴露出来的数据)则不被转换。 XmlSerializer 以及 Web Services 就使用这种技术。

Deep Serialization 比 Shallow Serialization 更加彻底,因为它是将存储在对象私有变量里的实际值拷贝到字节流里。而且 Deep Serialization 还将 serialize 整个 object graph 。也就是说,如果你的对象持有其他对象的引用,或者其他对象引用的集合,那么所有这些对象都将被 Serialize 。 BinaryFormatter 和 SoapFormatter 以及 .NET Remoting 都使用 Deep Serialization 技术,它甚至被有限地用于 LosFormatter 来产生存储在 Web Form 页中的状态数据。

本文将着重于 Deep Serialization 。

** Serialization ** ** 的过程 ** ** **


.NET Framework 通过 Reflection 提供自动 Serialization 的机制。当一个对象被序列化( Serialized )的时候,它的类名, Assembly ,以及类实例的所有数据成员都将被写入存储介质中。 Serialization 引擎保持对所有已经被序列化的对象引用的追踪,以确保相同的对象引用最多只被序列化一次。

通常,一个 Serialization 过程会由 formatter (例如 BinaryFormatter )的 Serialize 方法引发。对象的 Serialization 过程按照以下规则进行:

1、 检测以确保 formatter 是否拥有一个代理选择器( surrogate selector )。如果有,检查代理选择器是否持有给定的对象类型。如果有, ISerializable.GetObjectData 被调用。

2、 如果 formatter 没有代理选择器,或者代理选择器没有对象类型,检查对象是否被用 Serializable 属性标记。如果没有,则抛出 SerializationException 异常。

3、 如果对象被标记为 Serializable ,检查对象是否实现了 ISerializable 接口。如果实现了此接口,则 GetObjectData 被调用。

4、 如果对象没有实现 ISerializable 接口,则使用默认的序列化策略,来序列化没有用 NonSerialized 属性标记的域。

** 使你的 ** ** class ** ** 能够被序列化 ** ** **


通过上面对 Serialization 过程的分析,我们可以看出,有两种方式可以使一个 class 能够被序列化: 1 )将此 class 简单地标记为 Serializable ; 2 )为此 class 实现 ISerializable 接口,并将此 class 标记为 Serializable 。

** 1、 ** ** 标记 ** ** Serializable ** ** 属性 ** ** **

标记 Serializable 属性的方式是实现 Serialization 的基本方法。举个简单的例子:

[ Serializable ]

public class Person

{

public string name = null ;

public int age = 0;

}

你可以使用 BinaryFormatter 来将上面的 class 序列化:

Person sam = new Person ();

sam . name = "sam";

sam . age = 24;

IFormatter formatter = new BinaryFormatter ();

Stream stream = new FileStream ("sam.dat",

FileMode . Create , FileAccess . Write , FileShare . None );

formatter . Serialize ( stream , sam );

stream . Close ();

就是这么简单,你所要做的就是创建一个 Stream 和一个 formatter 的实例,然后调用 formatter 的 Serialize 方法。经过 BinaryFormatter serialize 的数据仍然能够通过 BinaryFormatter deserialize 回来,方法与 serialize 同样简单,这里就不赘述了。

如果你不想将类里的所有域都序列化,可以使用 NonSerialized 属性进行选择。如:

[ Serializable ]

public class Person

{

public string name = null ;

[Non Serialized ]

public int age = 0;

}

这样, age 域就不会被序列化了。

需要注意的是, Serializable 属性并不能被继承。也就是说如果你希望 Person 的派生类也能够被 Serialize 的话,那么这个派生类也必须被 Serializable 标记。否则将得到 SerializationException 异常。

同样的, Person 类中的所有对其他类的引用,其所引用的类都应该是能够被 Serialize 的。 .NET Framework 中的大部分 class 都实现了 ISerializable 接口,但有些 class 没有实现,例如 ImageList 。可以通过 MSDN Library 的到一个实现了 ISerializable 接口的 class 列表。对那些没有实现此接口的 class ,使用的时候要当心。

** 2、 ** ** 实现 ** ** ISerializable ** ** 接口 ** ** **

Serializable 属性的功能非常强大,它使得 Serialize 和 Deserialize 变得十分简单。但凡事有利必有弊,由 Serializable 实现的自动序列化方法有时不够灵活。我们并不能完全控制 Serialize 和 Deserialize 的行为,而有些时候它们的行为对我们来说很重要。那么我们通过何种方法能够控制 Serialize 和 Deserialize 的行为呢?答案就是,自己来实现 ISerializable 接口。 ISerializable 接口给予我们更大的自由来控制 Serialize 和 Deserialize ,但是无疑我们将不得不写更多的代码 L 。

下面我们来看看如何实现 ISerializabe 接口。 ISerializable 接口位于 System.Runtime.Serialization 名字空间中,声明如下:

public inferface ISerializable

{

void GetObjectData ( SerializationInfo info ,

StreamingContext context );

}

它只有一个方法 GetObjectData 。因此,像实现其他接口一样,我们必须实现此方法。但与其他接口不同的是,为了 Deserialization ,我们还必须实现一个特殊的构造函数(我称此构造函数为“序列化构造函数”),此构造函数具有与 GetObjectData 相同的参数列表。由于此构造函数专门用于 .NET Framework 在 Deserialize 时的 Reflection 机制,因此我们通常将它声明为保护或私有模式。如下:(当然,如果你的 class 只需要 Serialize 而不需要 Deserialize 的话,也可以不实现这个特殊的构造函数)

[ Serializable ]

public class Person : ISerializable

{

public string name = null ;

public int age = 0;

public Person ()

{

}

protected Person ( SerializationInfo info , StreamingContext context )

{

name = info . GetString ("name");

age = info . GetInt32 ("age");

}

void ISerializable . GetObjectData ( SerializationInfo info ,

StreamingContext context )

{

info . AddValue ("name", name );

info . AddValue ("age", age );

}

<SPAN style="ms

Published At
Categories with Web编程
Tagged with
comments powered by Disqus