Edward_jie

for you, my Hall of Frame

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

   一、概述
   
当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为对象。
    把对象转换为字节序列的过程称为
对象的序列化。
    把字节序列恢复为对象的过程称为对象的反序列化。

   二、对象的序列化主要有两种用途:
 
  1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
   
我们经常需要将对象的字段值保存到磁盘中,并在以后检索此数据。尽管不使用序列化也能完成这项工作,但这种方法通常很繁琐而且容易出错,并且在需要跟踪对象的层次结构时,会变得越来越复杂。可以想象一下编写包含大量对象的大型业务应用程序的情形,程序员不得不为每一个对象编写代码,以便将字段和属性保存至磁盘以及从磁 盘还原这些字段和属性。序列化提供了轻松实现这个目标的快捷方法。公共语言运行时 (CLR) 管理对象在内存中的分布,.NET 框架则通过使用反射提供自动的序列化机制。对象序列化后,类的名称、程序集以及类实例的所有数据成员均被写入存储媒体中。对象通常用成员变量来存储对其他实例的引用。类序列化后,序列化引擎将跟踪所有已序列化的引用对象,以确保同一对象不被序列化多次。.NET 框架所提供的序列化体系结构可以自动正确处理对象图表和循环引用。对对象图表的唯一要求是,由正在进行序列化的对象所引用的所有对象都必须标记为 Serializable(请参阅基 本序列化)。否则,当序列化程序试图序列化未标记的对象时将会出现异常。当反序列化已序列化的类时,将重新创建该类,并自动还原所有数据成员的值。
  2) 在网络上传送对象的字节序列。
  
对象仅在创建对象的应用程序域中有效。除非对象是从MarshalByRefObject派生得到或标记为 Serializable,否则,任何将对象作为参数传递或将其作为结果返回的尝试都将失败。如果对象标记为 Serializable,则该对象将被自动序列化,并从一个应用程序域传输至另一个应用程序域,然后进行反序列化,从而在第二个应用程序域中产生出该对象的一个精确副本。此过程通常称为按值封送。如果对象是从MarshalByRefObject派生得到,则从一个应用程序域传递至另一个应用程序域的是对象引用,而不是对象本身。也可以将从MarshalByRefObject派生得到的对象标记为Serializable。远程使用此对象时,负责进行序列化并已预先配置为SurrogateSelector的格式化程序将控制序列化过程,并用一个代理替换所有从MarshalByRefObject派生得到的对象。如果没有预先配置为SurrogateSelector,序列化体系结构将遵从下面的标准序列化规则.
四、基本序列化     要使一个类可序列化,最简单的方法是使用 Serializable 属性对它进行标记,如下所示:    

  [Serializable] 
     public class MyObject 
     { 
         public int n1 = 0; 
         public int n2 = 0; 
         public String str = null; 
     } 
 

  [BinarySerializer]

将此类的一个实例序列化为一个文件:  

MyObject obj = new MyObject(); 
 obj.n1 = 1; 
 obj.n2 = 24; 
 obj.str = "一些字符串"; 
 IFormatter formatter = new BinaryFormatter(); 
 Stream stream = new FileStream("MyFile.bin", FileMode.Create, 
 FileAccess.Write, FileShare.None); 
 formatter.Serialize(stream, obj); 
 stream.Close(); 

 

   反序列化:

IFormatter formatter = new BinaryFormatter(); 
 Stream stream = new FileStream("MyFile.bin", FileMode.Open, 
 FileAccess.Read, FileShare.Read); 
 MyObject obj = (MyObject) formatter.Deserialize(fromStream); 
 stream.Close(); 

 

  [XMLSerializer]   

将此类的实例序列化成一个Xml文件.

XmlSerializer ser = new XmlSerializer(obj.GetType());
 ser.Serialize(new FileStream(@"users.xml", FileMode.Create), obj);

 

   反序列化:

XmlSerializer serializer = new XmlSerializer(Type.GetType("MyObject"));
 MyObject my=(MyObject)serializer.Deserialize(new FileStream(@"users.xml",FileMode.Open));

 

    说明:使用二进制格式化程序进行序列化。您只需创建一个要使用的流和格式化程序的实例,然后调用格式化程序的 Serialize 方法。流和要序列化的对象实例作为参数提供给此调用。类中的所有成员变量(甚至标记为 private 的变量)都将被序列化,但这一点在本例中未明确体现出来。在这一点上,二进制序列化不同于只序列化公共字段的 XML 序列化程序。将对象还原到它以前的状态也非常容易。首先,创建格式化程序和流以进行读取,然后让格式化程序对对象进行反序列化。       

[SOAP Serializer]  

  如果要求具有可移植性,请使用 SoapFormatter。所要做的更改只是将以上代码中的BinaryFormatter换 SoapFormatter,而 Serialize 和 Deserialize 调用不变。

 

序列化和反序列化我们可能经常会听到,其实通俗一点的解释,序列化就是把一个对象保存到一个文件或数据库字段中去,反序列化就是在适当的时候把这个文件再转化成原来的对象使用。 我想最主要的作用有: 1、在进程下次启动时读取上次保存的对象的信息 2、在不同的AppDomain或进程之间传递数据 3、在分布式应用系统中传递数据 ...... 在C#中常见的序列化的方法主要也有三个:BinaryFormatter、SoapFormatter、XML序列化 本文就通过一个小例子主要说说这三种方法的具体使用和异同点
这个例子就是使用三种不同的方式把一个Book对象进行序列化和反序列化,当然这个Book类首先是可以被序列化的。至于怎么使一个类可以序列化可以参见:C#强化系列文章一:ViewState使用兼谈序列化

Book类

这个类比较简单,就是定义了一些public字段和一个可读写的属性,一个private字段,一个标记为[NonSerialized]的字段,具体会在下面的例子中体现出来
一、BinaryFormatter序列化方式1、序列化,就是给Book类赋值,然后进行序列化到一个文件中

            Book book =new Book();             book.BookID ="1";             book.alBookReader.Add("gspring");             book.alBookReader.Add("永春");             book.strBookName ="C#强化";             book.strBookPwd ="*****";             book.SetBookPrice("50.00");             BinarySerialize serialize =new BinarySerialize();             serialize.Serialize(book);

2、反序列化

            BinarySerialize serialize =new BinarySerialize();             Book book = serialize.DeSerialize();             book.Write();

3、测试用的

BinarySerialize类

主要就是调用System.Runtime.Serialization.Formatters.Binary空间下的BinaryFormatter类进行序列化和反序列化,以缩略型二进制格式写到一个文件中去,速度比较快,而且写入后的文件已二进制保存有一定的保密效果。 调用反序列化后的截图如下: 也就是说除了标记为NonSerialized的其他所有成员都能序列化
二、SoapFormatter序列化方式调用序列化和反序列化的方法和上面比较类似,我就不列出来了,主要就看看SoapSerialize类

SoapSerialize类

主要就是调用System.Runtime.Serialization.Formatters.Soap空间下的SoapFormatter类进行序列化和反序列化,使用之前需要应用System.Runtime.Serialization.Formatters.Soap.dll(.net自带的) 序列化之后的文件是Soap格式的文件(简单对象访问协议(Simple Object Access Protocol,SOAP),是一种轻量的、简单的、基于XML的协议,它被设计成在WEB上交换结构化的和固化的信息。 SOAP 可以和现存的许多因特网协议和格式结合使用,包括超文本传输协议(HTTP),简单邮件传输协议(SMTP),多用途网际邮件扩充协议(MIME)。它还支持从消息系统到远程过程调用(RPC)等大量的应用程序。SOAP使用基于XML的数据结构和超文本传输协议(HTTP)的组合定义了一个标准的方法来使用Internet上各种不同操作环境中的分布式对象。) 调用反序列化之后的结果和方法一相同
三、XML序列化方式调用序列化和反序列化的方法和上面比较类似,我就不列出来了,主要就看看XmlSerialize类

XmlSerialize类

从这三个测试类我们可以看出来其实三种方法的调用方式都差不多,只是具体使用的类不同 xml序列化之后的文件就是一般的一个xml文件:

book.xml

输出截图如下: 也就是说采用xml序列化的方式只能保存public的字段和可读写的属性,对于private等类型的字段不能进行序列化
关于循环引用: 比如在上面的例子Book类中加入如下一个属性:         public Book relationBook;在调用序列化时使用如下方法:

            Book book =new Book();             book.BookID ="1";             book.alBookReader.Add("gspring");             book.alBookReader.Add("永春");             book.strBookName ="C#强化";             book.strBookPwd ="*****";             book.SetBookPrice("50.00");             Book book2 =new Book();             book2.BookID ="2";             book2.alBookReader.Add("gspring");             book2.alBookReader.Add("永春");             book2.strBookName =".NET强化";             book2.strBookPwd ="*****";             book2.SetBookPrice("40.00");             book.relationBook = book2;             book2.relationBook = book;             BinarySerialize serialize =new BinarySerialize();             serialize.Serialize(book);

这样就会出现循环引用的情况,对于BinarySerialize和SoapSerialize可以正常序列化(.NET内部进行处理了),对于XmlSerialize出现这种情况会报错:"序列化类型 SerializableTest.Book 的对象时检测到循环引用。"

posted on 2012-06-02 00:38  Edward_诺  阅读(4467)  评论(0编辑  收藏  举报