首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

16章讲述了System.IO命名空间提供的功能,已经说到,该命名空间提供一些读写的类型用来在给定的位置(用给定的格式)对数据作持久化地保存。本章研究有关对象序列化object serialization的话题。使用对象序列化,你可以持久化保存一个对象的状态到任何System.IO.Stream派生的类型中(或是从后者中获取对象的状态)。

同读者设想的一样,当试图将一个对象复制到远程计算机(这个主题见下一章)时,具有对类型序列化的能力很关键。但一定要理解一点:序列化本身就非常有用,而在许多(分布式或非分布式的).NET应用程序中就更可能有用武之地。纵观本章,读者将学习到.NET序列化方案的方方面面,包括.NET 2.0引入的一组允许自定义进程的新特性。

17.1  对象序列化

术语序列化serialization)描述了持久化(可能还包括传输)一个对象的状态到流的过程。被持久化的数据次序包括所有以后需要用来重建(即反序列化)对象状态所必需的信息。使用这种技术,用最小花费来保存海量的(各种格式的)数据就变得轻而易举了。实际上,在很多情况下,使用序列化服务保存应用程序数据,相对直接使用System.IO命名空间的读取器/编写器,减少了很多的麻烦。

举例来说,设想你建立了一个基于GUI的桌面应用程序,并希望提供一种方法给最终用户保存他们偏好的界面。为此,你可能定义了一个名为UserPrefs的类用来封装20个字段数据模块。如果使用System.IO.BinaryWriter类型,需要人工保存UserPrefs对象每个字段成员;同样,当想从文件把这些数据导入内存的时候,需要使用System.IO.BinaryReader并且(再一次)人工地读入每个值以重新生成一个新的UserPref对象。

虽然这是可以实现的,但若为UserPrefs类标识[Serializable]特性将可以轻易地节省大量的时间。这时,对象全部的状态可以通过下面几行代码来持久化:

 

static void Main(string[] args)

{

    // 假设UserPrefs已被标识为[Serializable]

  UserPrefs userData= new UserPrefs();

  userData.WindowColor = "Yellow";

  userData.FontSize = "50";

  userData.IsPowerUser = false;

 

    // 现在将对象保存到一个名为user.dat的文件中。

  BinaryFormatter binFormat = new BinaryFormatter();

  Stream fStream = new FileStream("user.dat",

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

  binFormat.Serialize(fStream, userData);

  fStream.Close();

  Console.ReadLine();

}

 

虽然使用.NET对象序列化保存对象非常简单,但幕后的调用过程却非常复杂。例如,当一个对象被持久化到流时,所有的相关数据(基类、包含的对象等)也会被自动序列化,因此,假如你想持久化一个派生类,那么继承链(即基类,基类的基类)上的所有数据都会被包括进来,后面你会看到,一组相关的对象使用对象图来表现。

.NET序列化服务也允许用多种格式来保存一个对象图,先前的示例代码使用了BinaryFormatter类型,所以UserPrefs对象的状态被保存为紧凑的二进制格式。你也可以使用其他类型将对象图保存为简单对象访问协议(SOAP)或XML格式。当希望确保你的持久化对象跨越操作系统、语言和结构进行传递时,这些格式是很有用的。

最后,要知道对象图可以持久化为任意的System.IO.Stream派生类型。在先前的示例中,通过FileStream类型将UserPrefs对象持久化到一个本地文件。但是,如果你想保存对象到内存中,可以使用MemoryStream类型。关键是数据的顺序要正确地代表图中对象的状态。

对象图的作用

前面提到过,当对象被序列化时,CLR将处理所有相关的对象,一组关联对象被总称为一个对象图。对象图提供一种很简明的方式来记载一组对象如何相互引用对方,但又不见得映射到经典的面向对象的关系(譬如“is-a”或“has-a”的关系),尽管这些关系确实能详尽地描述词形变化。

在对象图中的每个对象被赋予一个独有的数值类型的值,谨记:这个数可值任意地赋给对象图中的成员,对外部世界没有真正意义。一旦所有的对象都赋予了数值,对象图就可以纪录每个对象的整个依赖关系。

举一个简单的例子,比如建立一组类模拟一些汽车,有一个基类名称是Car,它配有(“has-a”)Radio,另外一个名为JamesBondCar的类扩展Car基类,图17-1显示了一个模拟这些关系的可能的对象图。

17-1  简单的对象图

读取对象图时,可以使用短语“依赖于”(depend on)或“引用”(refer to)来表示连接箭头。因而,在图17-1里可以看到Car类引用了Radio类(有“has-a”关系)。JamesBondCar类引用了Car类(是“is-a”的关系)也引用了Radio(因为它继承了这个受保护的成员变量)。

当然,CLR不会在内存中画图来表示相关对象,上图中记载的关系会用类似下面这样的、更具有数学含义的公式来描述。

 

[Car 3, ref 2], [Radio 2], [JamesBondCar 1, ref 3, ref 2]

 

如果解析这个公式,会再次看到对象3Car类)依赖于对象2Radio类),对象2Radio类)像一个孤僻的人,不依赖任何人。最后,对象1JamesBondCar类)依赖于对象3和对象2,在各种情况下,序列化或反序列化JamesBondCar类的实例时,对象图确认Radio类型和Car类型也参与了这个过程。

序列化过程的美妙之处在于表示各个对象之间相互关系的图形是在幕后自动建立的。本章后面部分将会看到,如果希望更多地介入到某个对象图的构建,也是可以做到的。

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论