65.9K
CodeProject 正在变化。 阅读更多。
Home

.NET Framework 运行时序列化

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (2投票s)

2009年5月22日

CPOL

6分钟阅读

viewsIcon

47149

downloadIcon

403

本文聚焦于对象序列化。

引言

任何接触过文档部分的人都知道,文档的不同区域——保存图像和徽标、文本字段和控件的区域——在内存中的存储方式不同。事实上,当我们开发 .NET 应用程序时,可能不会考虑数据在内存中是如何存储的。框架会为您处理。但是,如果您想将一个对象的内容存储到文件中,将一个对象发送到另一个进程,或者通过网络传输它,您确实需要考虑对象是如何表示的,因为您需要将其转换为不同的格式。这种转换称为序列化。更确切地说,由于 CLR 使用自动内存管理来跟踪对象的生命周期,方法是维护一个可访问对象(因此仍然可用)的图,序列化就是将一个对象或一个连接的对象图转换为连续字节流的过程。反序列化是将连续字节流转换回其连接对象图的过程。将对象转换为字节流以及从字节流中转换回对象的能力提供了许多有用且实用的机制。

  • 应用程序的状态(对象图)可以轻松地保存在磁盘文件或数据库中,并在下次运行应用程序时恢复。ASP.NET 通过序列化和反序列化来保存和恢复会话状态。
  • 一组对象可以轻松地复制到系统的剪贴板,然后粘贴到同一个或另一个应用程序中。事实上,Windows® Forms 就是使用这个过程。
  • 一组对象可以被克隆并放在一边作为备份,而用户则可以操作主要的这组对象。
  • 一组对象可以很容易地通过网络发送到运行在另一台机器上的进程。.NET Framework 远程处理架构会序列化和反序列化按值封送的对象。

本文将重点介绍在 System.Runtime.Serialization 命名空间中实现的序列化。序列化和反序列化对象允许它们被存储或传输,然后在之后重新创建。序列化对象会将对象转换为一个线性的字节序列,该序列可以被存储或传输。反序列化对象会将先前序列化的字节序列转换为一个对象。

如何序列化对象

高层次上,序列化对象的步骤如下:

  1. 创建一个流对象来保存序列化输出。
  2. 创建一个 BinaryFormatter 对象。
  3. 调用 BinaryFormatter.Serialize 方法来序列化对象,并将结果输出到流。

考虑这段序列化字符串数据的基本代码:

using System;
using System.Runtime.Serialization;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

public sealed class Program {
    public static void Main() {

        string data = "this must be stored in a file";
        // create the file to store the data to
        FileStream fs = new FileStream("SerializedString.Data", 
                                       FileMode.Create);

        // create binary formatter object to perform serialization
        BinaryFormatter bf = new BinaryFormatter();

        // use the BinaryFormatter object to serialize the data to the file
        bf.Serialize(fs, data);
        fs.Close();
    }
}

编译此代码后,我们使用命令 'notepad SerializedString.Data'

Capture.JPG

序列化的对象可以存储为文件,但不是文本文件。

现在,考虑这段反序列化文件中存储对象的代码:

using System;
using System.Runtime.Serialization;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

public sealed class Program {
    public static void Main() {
        //notice that the FileMode is now Open and not Create
        FileStream fs = new FileStream("SerializedString.Data", 
                                       FileMode.Open);
        BinaryFormatter bf = new BinaryFormatter();

        string data = "this must be stored in a file";
        data = (string) bf.Deserialize(fs);
        fs.Close();
        Console.WriteLine(data);
    }
}

这是输出,或初始用于将对象转换为连续字节流的逆过程:

1.JPG

一个字符串数据需要被转换为对象,然后序列化并存储在文本文件中,这种情况不太可能发生,但这个例子是为了说明本文主题背后的基本原理。为此,请考虑另一个例子:

using System;
using System.Runtime.Serialization;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

public sealed class Program {
    public static void Main() {
        FileStream fs = new FileStream("SerializedString.Data", 
                                       FileMode.Create);
        BinaryFormatter bf = new BinaryFormatter();
        bf.Serialize(fs, System.DateTime.Now);
        fs.Close();
    }
}

输出如下

C:\Windows\MICROS~1.NET\FRAMEW~1\V20~1.507>ser2.exe
C:\Windows\MICROS~1.NET\FRAMEW~1\V20~1.507>notepad SerializedString.Data

2.JPG

再次,这是反序列化文件中存储为字节流的对象的代码:

using System;
using System.Runtime.Serialization;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

public sealed class Program {
    public static void Main() {
        FileStream fs = new FileStream("SerializedString.Data", 
                                       FileMode.Open);
        BinaryFormatter bf = new BinaryFormatter();
        DateTime previousTime = new DateTime();
        previousTime = (DateTime) bf.Deserialize(fs);
        fs.Close();
        Console.WriteLine("Day: " + previousTime.DayOfWeek + 
                ", Time: " + previousTime.TimeOfDay.ToString());
    }
}

输出:

3.JPG

读者应该注意到,运行时内部的反序列化过程可能非常复杂。CLR 顺序进行反序列化过程,从头开始,一直工作到最后。请记住,序列化是将对象转换为连续字节流的过程。如果序列化流中的对象引用另一个对象,则该过程会变得复杂。如果一个对象引用另一个对象,格式化程序(稍后将讨论)会查询对象管理器,以确定引用的对象是否已被反序列化(连续流中的后向引用),或者它是否尚未被引用(前向引用)。

XML 序列化

XML 是一种标准化的、基于文本的文档格式,用于存储应用程序可读的信息。就像 HTML 为格式化人类可读文档提供了一种基于文本的标准一样,XML 提供了一种可以轻松由计算机或任何联网机器处理的标准。使用 XML 序列化对象的步骤是:

  1. 创建一个流、TextWriterXmlWriter 对象来保存序列化输出。
  2. 创建一个 XMLSerializer 对象(在 System.Xml.Serialization 命名空间中),并将您计划序列化的对象类型传递给它。
  3. 调用 XmlSerializer.Serialize 方法来序列化对象,并将结果输出到(步骤 1 中)先前创建的流。
<?xml version="1.0"?>
<dateTime>2009-05-23T17:07:45.8726619-04:00>

要使用 XML 反序列化对象,您应该遵循以下步骤:

  1. 创建一个流、TextReaderXmlReader 对象来保存序列化输出。
  2. 创建一个 XMLSerializer 对象(在 System.Xml.Serialization 命名空间中),并将您计划反序列化的对象类型传递给它。
  3. 调用 XmlSerializer.Deserialize 方法来序列化对象,并将其强制转换为正确的类型。

这是用于反序列化对象的示例代码:

using System;
using System.Runtime.Serialization;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Xml.Serialization;

public sealed class Program {
    public static void Main() {

        // create a file to save the data to
        FileStream fs = new FileStream("SerializedString.Date", FileMode.Open);

        // create an XmlSerializer object to perform the serialization
        XmlSerializer xs = new XmlSerializer(typeof(DateTime));

        // use the XmlSerializer object  to serialize the data to a file
        DateTime previousTime = (DateTime)xs.Deserialize(fs);

        // close the file
        fs.Close();

        // display the deserialized time
        Console.WriteLine("Day: " + previousTime.DayOfWeek + 
                " ,Time: " + previousTime.TimeOfDay.ToString());
    }
}

输出

4.JPG

选择序列化格式

到目前为止,我们使用了 System.Runtime.Serialization.Formatters.Binary 命名空间中的 BinaryFormatter。此格式化程序是序列化仅会被 .NET Framework 应用程序读取的对象的最高效方式。SoapFormatter 位于 System.Runtime.Serialization.Formatters.Soap 命名空间中,它是基于 XML 的,主要用于 SOAP Web 服务。要使用 SoapFormatter,请将 SoapFormatter 类替换为 BinaryFormatters 类。下面是一个示例。顺便说一句,要使用这些示例,请在框架命令提示符下键入 *type con > NameOfFile.cs*,复制代码并将其粘贴到控制台,按 Ctrl-Z,然后编译代码。

using System;
using System.Runtime.Serialization;
using System.IO;
using System.Runtime.Serialization.Formatters.Soap;

public sealed class Program {
    public static void Main() {
        FileStream fs = new FileStream("SerializedString.Date", 
                                       FileMode.Create);
        SoapFormatter sf = new SoapFormatter();
        sf.Serialize(fs, System.DateTime.Now);
        fs.Close();
    }
}

编译并运行示例,然后使用 Notepad 命令处理 SerializedString.Date

<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/" 
    xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" 
    SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<xsd:dateTime id="ref-1">
<ticks>633786999834950619</ticks>
<dateData>9857159036689726427</dateData>
</xsd:dateTime>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

整合

我们现在知道,序列化是运行时将一个对象或一个对象图转换为线性字节序列的过程。然后,您可以使用生成的内存块来存储或在特定协议之上通过网络传输。在 .NET 对象序列化中,我们可以有三种输出形式:二进制、SOAP 和 XML。运行时对象序列化(例如,二进制和 SOAP)和 XML 序列化是不同的技术,具有不同的实现和目标。要使用 SoapFormatter,您必须引用一个单独的程序集:*System.System.Runtime.Serialization.Formatters.Soap.dll*,通过导入该命名空间。

using System.Runtime.Serialization.Formatters.Soap;

XML 序列化由 XmlSerializer 类处理。它类似于二进制和 SOAP 格式化程序,因为它也持久化和恢复对象的状态。将下载的文件解压缩到 Visual Studio 2005(8) 项目文件夹中新建的一个文件夹中,然后双击解决方案文件。这个 Windows Forms 应用程序将使您能够更清晰地了解这些序列化技术。

© . All rights reserved.