黑马程序员- C# - 序列化和反序列化

来源:互联网 发布:虚拟服务器端口设置 编辑:程序博客网 时间:2024/05/18 15:28

-------------------------------------------- ASP.Net+Android+IO开发、.Net培训、期待与您交流! -----------------------------------

                                                                                                      C# -序列化和反序列化

一、序列化的概念

序列化就是把一个对象保存到一个文件或数据库字段中去,反序列化就是在适当的时候把这个文件再转化成原来的对象使用。

  需要分清楚的概念对象的序列化而不是类的序列化。对象的序列化表明C#提供了将运行中的对象(实时数据)写入到硬盘文件或者数据库中,此功能可以运用在需要保留程序运行时状态信息的环境下

  使用序列化有两个最重要的原因:

一个原因是将对象的状态永久保存在存储媒体中,以便可以在以后重新创建精确的副本;

另一个原因是通过值将对象从一个应用程序域发送到另一个应用程序域中。

  前提:要将对象的类声明为可以序列化。

作用:

1、在进程下次启动时读取上次保存的对象的信息 

2、在不同的AppDomain或进程之间传递数据 

3、在分布式应用系统中传递数据

自己做的例子:

(注意:一定不要忘了在要序列化的类上,加上[Serializable]

publicvoid Load()

        {

this.soldTickets =newList<Ticket>();

this.Seats =newDictionary<string,Seat>();

if (File.Exists("listticketsold.txt"))

            {

FileStreamfs =newFileStream("listticketsold.txt",FileMode.Open);

BinaryFormatter bf =newBinaryFormatter();

this.soldTickets = (List<Ticket>)bf.Deserialize(fs);

fs.Close();

            }

if (File.Exists("seatbiarray.txt"))

            {

FileStreamfs =newFileStream("seatbiarray.txt",FileMode.Open);

BinaryFormatter bf =newBinaryFormatter();

this.Seats = (Dictionary<string,Seat>)bf.Deserialize(fs);//此处用于反序列化

fs.Close();

            }

        }

publicvoid Save(List<Ticket>listticket,Dictionary<string,Seat>seatsbitarray)//此处用于序列化

        {

FileStreamfs =newFileStream("listticketsold.txt",FileMode.Create);

BinaryFormatter bf =newBinaryFormatter();

bf.Serialize(fs, listticket);

fs.Close();

FileStreamfss =newFileStream("seatbiarray.txt",FileMode.Create);

BinaryFormatterbff =newBinaryFormatter();

bff.Serialize(fss,seatsbitarray);

fss.Close();

        }

 

二、永久存储

通常需要将一个对象的各字段的值存储到磁盘中,这样以后可以检索这些数据。尽管不依赖序列化也可以很容易地做到这一点,但这样的方法通常十分麻烦并且容易出错,在您需要跟踪对象的层次结构时将变得越来越复杂。设想一下编写包含数以千计对象的大型商业应用程序,将不得不为每一对象编写代码以将字段和属性保存到磁盘上和从磁盘上还原它们,这是多么的复杂。而序列化为实现上述目标提供了一个方便的机制。

公共语言运行库管理对象在内存中的存储方式并通过使用反射提供自动的序列化机制。当序列化一个对象时,类的名称、程序集和类实例的所有数据成员都被写入存储中。对象通常在成员变量中存储对其他实例的引用。在序列化类时,序列化引擎跟踪已被序列化的引用对象,以确保同一对象不会被多次序列化。随一起提供的序列化结构自动正确处理对象图和循环引用。对于对象图的唯一要求就是,由被序列化的对象引用的所有对象还必须标记为 Serializable。如果没有进行此标记,当序列化程序尝试序列化未标记的对象时,将引发一个异常。

当反序列化已序列化的类时,重新创建该类并且自动还原所有数据成员的值。

 

三、值封送

  对象只在创建它们的应用程序域中有效。将对象作为一个参数传递或将其作为结果返回的任何尝试都将失败,除非该对象派生自 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;

}

以下代码示例说明该类的实例是如何被序列化到一个文件中的。

MyObject obj = new MyObject();

obj.n1 = 1;

obj.n2 = 24;

obj.str = "Some String";

IFormatter formatter = new BinaryFormatter();

Stream stream = new FileStream("MyFile.bin", FileMode.Create, FileAccess.Write, FileShare.None);

formatter.Serialize(stream, obj);

stream.Close();

该示例使用二进制格式化程序执行序列化。您需要做的所有工作就是创建流的实例和您想要使用的格式化程序,然后对该格式化程序调用 Serialize方法。要序列化的流和对象作为参数提供给该调用。尽管在此示例中并没有显式阐释这一点,但一个类的所有成员变量都将被序列化,即使是那些已标记为私有的变量。在此方面,二进制序列化不同于 XMLSerializer类,后者只序列化公共字段。

将对象还原回其以前的状态十分简单。首先,创建用于读取的流和格式化程序,然后指示格式化程序反序列化该对象。下面的代码示例说明如何执行上述的操作。

IFormatter formatter = new BinaryFormatter();

Stream stream = new FileStream("MyFile.bin", FileMode.Open, FileAccess.Read, FileShare.Read);

MyObject obj = (MyObject) formatter.Deserialize(stream);

stream.Close();

 

// Here's the proof.

Console.WriteLine("n1: {0}", obj.n1);

Console.WriteLine("n2: {0}", obj.n2);

Console.WriteLine("str: {0}", obj.str);

上面所用的 BinaryFormatter非常有效,生成了非常简洁的字节流。通过该格式化程序序列化的所有对象也可以通过该格式化程序进行反序列化,这使该工具对于序列化将在 .NET Framework上被反序列化的对象而言十分理想。需要特别注意的是,在反序列化一个对象时不调用构造函数。出于性能方面的原因对反序列化施加了该约束。但是,这违反了运行库与对象编写器之间的一些通常约定,开发人员应确保他们在将对象标记为可序列化时了解其后果。

如果可移植性是必需的,则转为使用 SoapFormatter。只需用 SoapFormatter 代替上面代码中的 BinaryFormatter,并且如前面一样调用 Serialize Deserialize。此格式化程序为上面使用的示例生成以下输出。

 

<SOAP-ENV:Envelope

  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  xmlns:xsd="http://www.w3.org/2001/XMLSchema"

  xmlns:SOAP- ENC="http://schemas.xmlsoap.org/soap/encoding/"

  xmlns:SOAP- ENV="http://schemas.xmlsoap.org/soap/envelope/"

  SOAP-ENV:encodingStyle=

  "http://schemas.microsoft.com/soap/encoding/clr/1.0"

  "http://schemas.xmlsoap.org/soap/encoding/"

  xmlns:a1="http://schemas.microsoft.com/clr/assem/ToFile">

 

  <SOAP-ENV:Body>

    <a1:MyObject id="ref-1">

      <n1>1</n1>

      <n2>24</n2>

      <str id="ref-3">Some String</str>

    </a1:MyObject>

  </SOAP-ENV:Body>

</SOAP-ENV:Envelope>

需要特别注意的是,Serializable属性不能被继承。如果我们从 MyObject 派生一个新类,此新类必须也用该属性标记,否则将无法被序列化。例如,当试图序列化下面的类的实例时,您将获得 SerializationException,通知您 MyStuff类型没有标记为可序列化。

 

 

 

 

-------------------------------------------- ASP.Net+Android+IO开发、.Net培训、期待与您交流! -----------------------------------

 

原创粉丝点击