.NET中的序列化

来源:互联网 发布:为什么淘宝分享打不开 编辑:程序博客网 时间:2024/05/21 21:33

序列化定义          序列化是将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。在此过程中,先将对象的公共字段和私有字段以及类的名称(包括类所在的程序集)转换为字节流,然后再把字节流写入数据流。在随后对对象进行反序列化时,将创建出与原对象完全相同的副本。


序列化的目的 1、以某种存储形式使自定义对象持久化; 2、将对象从一个地方传递到另一个地方。
3、对象封送,远程服务甚至网络数据流都运用了序列化的技术。
序列化运行机制          实质上序列化机制是将类的值转化为一个一般的(即连续的)字节流,然后就可以将该流写到磁盘文件或任何其他流化目标上。将对象的状态信息转换为可以存储或传输的窗体的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。序列化使其他代码可以查看或修改那些不序列化便无法访问的对象实例数据。确切地说,代码执行序列化需要特殊的权限:即指定了 SerializationFormatter 标志的 SecurityPermission。在默认策略下,通过 Internet 下载的代码或 Intranet 代码不会授予该权限;只有本地计算机上的代码才被授予该权限。通常,对象实例的所有字段都会被序列化,这意味着数据会被表示为实例的序列化数据。这样,能够解释该格式的代码有可能能够确定这些数据的值,而不依赖于该成员的可访问性。类似地,反序列化从序列化的表示形式中提取数据,并直接设置对象状态,这也与可访问性规则无关。对于任何可能包含重要的安全性数据的对象,如果可能,应该使该对象不可序列化。如果它必须为可序列化的,请尝试生成特定字段来保存不可序列化的重要数据。如果无法实现这一点,则应注意该数据会被公开给任何拥有序列化权限的代码,并确保不让任何恶意代码获得该权限。
序列化的应用          1、在用户登录后,对界面作一些个性化设置(如:背景色,布局,字体等),为了使用用户关闭网页后能够保留设置,以便在下次登录时再加载上次的设置,我们可以将用户的设置信息保存在一个对象中,然后把该对象序列化保存在表的某个字段中,在加载网页的时候取出字段中的信息,并反序列化生成设置对象,应用到用户界面上。          2、对用户的一些不用作查询的信息(如:住址,Email,家庭成员,工作经历等)序列化后保存在一个表的字段中,在需求发生变化时(如增加用户新的信息),不用动态增加字段。在需要使用的时候,取出字段中的信息反序列化成对象就可以了。          3、在点对点两人聊天系统中,一个用户输入的内容(如:彩色文字,图片等)后显示输入时的内容和样式,另一个用户界面中也应当显示同样的内容和样式。这时我们可以把用户输入的内容(如:彩色文字,图片等)封装为一个对象,然后序列化到二进制网络流中去,在另一端,取出二进制流并反序列化成对象,然后显示在界面上。

序列化种类          .NET框架提供两种格式的序列化,二进制序列化(Binary Serialization)和XML序列化(XML Serialization)。

         1. 二进制序列化:将对象分解成为简单的二进制格式,这种类型的序列化并不会遗失原来的类型数据,对象使用二进制序列化分解之后,可以被传送至各种存储媒介,包括数据流,磁盘,内存甚至网络上连接的主机。          2. XML序列化:将对象分解成为XML格式,使用SOAP标准来访问,由于XML与SOAP是开放标准,因此特别适用于对象需要跨越网络传送的情形,与二进制序列化不同的是,使用这种格式的序列化,只会序列化分解类型中的公用(Public)属性和字段等内容。

序列化类的功能          .NET框架针对两种不同格式的序列化技术,均提供了相应的类:BinaryFormatter类以及SoapFormatter ,XmlSerializer类。

BinaryFormatter用于二进制格式序列化的操作,位于如下命名空间中: System.Runtime.Serialization.Formatters.Binary

SoapFormatter提供XML序列化的支持,其所处的命名空间如下: System.Runtime.Serialization.Formatters.Soap

XmlSerializer提供XML序列化支持,所处命名空间为: System.Xml.Serialization

        这三种类提供对象序列化分解操作以及还原序列化的相关方法,简化序列化对象所需的实现细节。而要想实际的写出这个流,就要使用那些实现了IFormatter接口的类里的Serialize和Deserialize方法。

1.BinaryFormatter类用来将对象进行二进制的格式化分解,并将二进制格式化分解的对象组合还原,Serialize() 以及Deserialize() 方法分别用来序列化以及还原序列化。下面是Serialize() 方法的定义: Public void Serialize(Stream,object);此方法接受stream类型以及object类型对象参数,将其中object类型对象序列化之后,传递到第1个参数所指定的数据流对象。下面是还原序列化的方法Deserialize() 的定义,这个方法将上面序列化分解的对象重新组合还原,以取得原始对象: Public object Deserialize(Stream serializationStream);其中Stream类型参数便是所要还原的数据流,Deserialize方法从这个数据流对象中重新组合还原被序列化分解的对象。

2.SoapFormatter类用来将对象序列化分解为SOAP格式以及还原序列化对象,这个类同样提供序列化对象以及还原序列化操作的方法,名称同样为Serialize() 以及Deserializ() ,甚至所接受的参数值与上面的BinaryFormatter类也相同。

当要将一个类的实例对象进行序列化分解之前,首先必须要确认这个类是否可以进行序列化分解,一个类通常通过属性 [Serializable] 将其标注为可序列化(XmlSerializer方法可以不标注而直接序列化),换句话说,可以依据所要序列化分解的格式,使用上面任一个类对标注为 [Serializable] 的类实例对象进行序列化分解。当然,在序列化对象时,也可以使用属性 [NonSerialized] ,将对象中的某些成员标注为不可序列化,有选择性的只分解对象中的某些数据成员,那些标注为 [NonSerialized] 的数据成员,在对象的序列化过程中将不会被分解。

3. XmlSerializer类用来将对象序列化分解为XML格式以及还原序列化对象,实现方法同上。

XmlSerializer支持很多特性(ATTRIBUTES),它们可以用于为特定的类设定序列化方式。例如,可将某个字段或属性标以 [XmlIgnore] 特性,从而将其排除在序列化机制之外。另外 [XmlElement] 可用于指定XML元素名称(这个元素名称被用于特定的属性或字段)。

对于经由SoapFormatter,BinaryFormatter的序列化,也可以使用特性进行某种程度的控制。例如,[NonSerialized] 特性等价于XmlSerializer的 [XmlIgnore] 特性。对序列化过程的终极控制,可以通过在其实休打算被序列化的类上,实现ISerializable接口。XmlSerializer不能用于序列化任何实现了IDictionary接口的类的实体,比方说Hashtable(散列表),而SoapFormatter和BinaryFormatter却没有这个限制。

微软将XmlSerializer用于Web Services,而将BinaryFormatter和SoapFormatter用于远程化。

序列化类使用选择         可以依据具体情况来进行有效。XmlSerializer的限制比较严格,比如,要求目标类有一个无参数的构造器,并且只有公开的读,写属性和字段时才可被序列化。不过,从好的方面说,XmlSerializer对定制XML文档提供了良好的支持。XmlSerializer的特性意味着,它最适合用在跨平台的情况下,或者用于从现有的XML文档构建对象。SoapFormatter和BinaryFormatterXmlSerializer的限制要少,它们可以序列化私有字段。然而,它们都需要目标类标以 [Serializable] 特性,因此,像XmlSerializer一样,需要小心以序列化方式来编写类。有些诡异的东西也是要小心提防的。在反序列化时,新对象的构造器并不被调用。对SoapFormatter和BinaryFormatter的选择,取决于应用。BinaryFormatter对于序列化和反序列化都是发生在.NET平台上并且执行性能很重要的情况大有用处。通常来说,在所有其它情况下,SoapFormatter更有意义,也更易于调试。

自定义序列化自定义序列化行为          序列化与还原序列化均由指定的Formetter自动完成。也可以选择实现ISerializable接口,自行创建专属的Formetter,以达到自行控制对象序列化及还原序列化的目的。在某些情形下,我们特别需要序列化的过程,例如若变量值的内容在序列化之后会失去原先存储的值,此时你便可以自定义序列化的行为,强迫恢复原先的内容。你可以在对象序列化的过程中,进一步使用加密技术,改变数据的格式,在反序列化操作的时候,以相对的解密技术将数据还原。自定义序列化的行为允许你设计序列化对象的过程,而不是直接将指定的对象分解然后放入网络或是存储到数据流,避免数据的遗失,甚至在序列化进程发生不当撷取的情形。 ? 自定义序列化方法实现ISerializable接口可以帮助你自定义对象的序列化行为,继承这个接口的类,必须同时实现方法GetObjectData() 和Constructor构造函数。

GetObjectData() 用来将对象相关信息填入SerializationInfo对象,其定义如下: Void GetObjectData(SerializationInfo info,StreamingContext context);其中的info是SerializationInfo类型的对象参数。SerializationInfo类被设计用来存储对象自定义序列化操作时所需的信息,context是一种StreamingContext结构类型参数,表示序列化操作的来源数据流。

除了实现GetObjectData() 方法外,自定义序列化的过程,还必须完成特定构造函数的实现,构造函数在对象还原序列化时,将上面的info 参数内容传递到类。实现构造函数,必须引用SerializationInfo所定义的实例方法GetValue() ,提供指定的成员变量值。其特定构造函数形式如下: Public 类名(SerializationInfo info,StreamingContext context);

ISerializable接口位于System.Runtime.Serialization命名空间,在实现接口之前,必须引用这个命名空间。

序列化属性的继承          对象的序列化属性没有办法被继承,换句话说,继承标注为 [Serialized] 类的子类,由其创建的实例对象,并没有办法被序列化,除非你明确地将其标注为[Serialized],如果基类同时亦实现接口ISerializable,派生的子类同样也必须实现方法GetObjectData() 以及构造函数,才能够自定义序列化成员变量的相关程序。另外在还原序列化重组对象时所调用的构造函数,同样必须继承基类。

序列化数据的修正          当一个成员变量被标注为 [NonSerialized] 时,由于在对象序列化的过程中,成员变量并没有被分解,当进行还原序列化操作,即重组对象的时候,所得到的将不是原先的成员变量的值。如果想要改变这种预设行为,可以在设计类的时候,继承IDeserializationCallback接口,实现方法OnDeserialization() ,还原正确的数据值。

方法OnDeserialization() 的定义如下: Void OnDeserialization(object sender);

继承IDeserializationCallback接口的类对象,在还原序列化的时候,会先调用OnDeserialization() 方法,执行其中的方法。

当我们操作一个包含大量的暂时性数据对象,而此时序列化对象的时候,会同时分解这些暂时性数据,连同分解后的对象一并写入文件,可以想象,这种作法非但没有意义,而且浪费资源。这时可以选择先把这些数据成员标注为 [NonSerialized] ,然后在还原序列化,重组对象的同时,调用方法OnDeserialization() ,还原先前未被序列化分解的成员变量,这样一来,除了序列化的过程比较有效率外,还能够兼顾数据的正确性。