二进制和XML串行化的比较
象上面表明的那样,选择XML或二进制串行化不取决于代码的实现。二种方法实现起来都非常简单。下面我们来考虑二种方法各自的优点。
二进制串行化的优点 1、无论是否是只读属性,所有成员都将被串行化。
2、更高的性能。
XML串行化的优点 1、对象共享和使用方面更大的灵活性(互操作性)。
2、不严格的二进制依赖
3、可读性
在研究Figure 1.1中的代码后,我们会发现,二进制和XML串行化仅仅依赖于对Formatter的选择。我们还会发现,串行化和反串行化之间的差别就在于是调用Serialize()还是Deserialize()。上面的代码能够原封不动地拷贝到我们的应用程序中,它将成为我们大多数串行化需求的核心
基本串行化和定制串行化的比较
.NET Framework提供了二种完成串行化的方式。需要记住的是,完成串行化的方式与串行化的格式是二个不同的概念,执行串行化是指.NET Framework如何获得我们对象、以及如何将它转化为最后结果的实际方式,与格式(二进制还是XML格式无关)。最简单的方法是让.NET Framework自动地对对象进行串行化操作,这种方式被称作“基本串行化”。“基本串行化”只要求对象拥有类属性[Serializable()]即可,.NET Framework将获得我们的类,并将它转换为给定的格式。在这种方法中,我们唯一能够施加影响的是,使用[NonSerialized()]字段属性使任何字段式不会被串行化,我们无法对类中的每个字段是如何被串行化的提供精确的控制。
如果希望对串行化处理有更多的控制,就需要使用“定制串行化”。在这种方式中,我们能够精确地指定哪个字段能够被串行化,以及如何进行串行化。在样例解决方案中,我们创建了一个名字为ScheduleCustom的类,正确地演示了“定制串行化”的用法。
在使用“基本串行化”时,对象的版本是一个主要问题。要将Schedule对象串行化到磁盘上,然后改变该对象(例如,添加一个字段),在进行反串行化时就会出现问题,得到如下所示的错误信息:
“成员的数量发生错误,FifteenSeconds.Schedule对象有4个成员,被反串行化的成员数量为3。”
如果碰上这一问题,就要考虑使用“定制串行化”了。由于能够在串行化处理过程中精确地控制类中的所有成员,我们就能够解决因版本而出现的问题。
定制串行化 我们需要作的第一件事就是明确地在类前面添加[Serializable()];第二,我们的类必须实现
System.Runtime.Serialization.ISerializable接口,因此,我们的类的定义应当如下所示:
[Serializable()] public class ScheduleCustom : System.Runtime.Serialization.ISerializable { //在接口中,我们能够发现下面的一个方法: void GetObjectData(SerializationInfo info, StreamingContext context); //为了使类能够很好地支持这一接口,我们还必须实现下面的GetObjectData()方法: public void GetObjectData(SerializationInfo info,StreamingContext context) { //利用info对象添加需要进行串行化的字段 info.AddValue("start", start); info.AddValue("end", end); info.AddValue("interval", interval); } |
仅仅通过上面这个简单的例子,我们也许还不能深刻地体会到使用“定制串行化”的强大功能。下面,我们将增加类的复杂程度,演示“定制串行化”带给我们串行化需求的灵活性:
如果我们要检查串行化过程中开始时DateTime值的输出,就会发现它使用了缺省的Framework DateTime格式:
2002-08-19T14:09:13.3457440-07:00
如果要与其他不使用.NET Framework的人合作,并国际化地发布应用程序,用格林威治时间来表示
DateTime值是比较明智的。下面我们来修改GetObjectData()方法,将开始和结束时的值转换为格林威治时间。
public void GetObjectData(SerializationInfo info,StreamingContext context) { //使用info对象添加需要串行化的字段 //为了更好地与别人合作,我们将把时间转换为格林威治时间 info.AddValue("start", System.TimeZone.CurrentTimeZone.ToUniversalTime(start)); info.AddValue("end", System.TimeZone.CurrentTimeZone.ToUniversalTime(end)); info.AddValue("interval", interval); info.AddValue("timeformat", "utc"); } |
8/19/2002 9:09:13 PM
现在,转换时的起始时间将成为如下的格林威治时间形式:
8/19/2002 9:09:13 PM
注意,我添加了一个名字为“timeformat”的属性,在以后判断在串行化处理中使用哪种时间格式时,这一字段特别有用。
也可以考虑用其他格式输出日期。考虑System.Globalization.DateTimeFormatInfo能够提供哪几种格式,例如,将DateTime转换为自Unix“诞生”(1979年1月1日)后的时间,这样可以更好地与非微软的平台进行集成)。我们也可以在类中添加一个可选的属性,判断在被串行化时DateTime使用的格式。
定制反串行化 如果希望使对象能够以定制方式被反串行化,需要使用一个定制构建器。该构建器的定义如下所示:
public ScheduleCustom (SerializationInfo info,StreamingContext context) {} |
我们必须实现这一方法。在schedule类中,我们的实现将把UTC(世界协调时间)转换为本机上的DateTime格式。
public ScheduleCustom (SerializationInfo info,StreamingContext context) { //我们将日期/时间转换回本地时间 this.start = info.GetDateTime("start").ToLocalTime(); this.end = info.GetDateTime("end").ToLocalTime(); this.interval = info.GetInt32("interval"); } |
象我们在前面的“定制串行化”过程中指出的那样,添加的timeformat字段能够用来指定如何将串行化的时间转换为本地对象所必需的DateTime格式,但由于在本例中我们只进行了与UTC时间之间的转换,因此是相当简单的。
使用Web服务的串行化 在学习新的技术时,最重要的是学习这种技术如何使用。在这一部份中,我们将创建一个有二个方法的Web服务:第一个方法使Framework以二进制的形式返回我们定制串行化的schedule对象,第二个方法以XML的格式返回相同的对象。
我们只要简单地添加一个带有指向上面的串行化工程引用的新C# Web服务工程即可,然后,我们再创建上面所述的二个方法:
FifteenSeconds.ScheduleCustom customSchedule = new FifteenSeconds.ScheduleCustom(System.DateTime.Now, System.DateTime.Now.AddHours(5), 10000);
[WebMethod] public byte[] Get_Binary_Schedule() { return FifteenSeconds.Serializer.Serialize( customSchedule, FifteenSeconds.Serializer.SerializationFormat.Binary).ToArray(); } [WebMethod] public string Get_XML_Schedule() { return FifteenSeconds.Serializer.ConvertStreamToString (FifteenSeconds.Serializer.Serialize( customSchedule, FifteenSeconds.Serializer.SerializationFormat.Xml)); } |
需要注意的是,二个方法都使用了FifteenSeconds.ScheduleCustom对象的同一个实例,在二进制形式中返回byte[]型数据,在XML形式中返回string型数据。
需要记住的是,Framework将自动地串行化我们的对象,根据使用的方法返回适当类型的数据。另外,我们还需要一些时间研究解决方案中的Serialization工程,在将这些对象串行化为一个文件时,其中有些方法可能会有用。
结论 这篇文章演示了在应用程序中使用串行化是如何简单。在需要将一个对象的实例转换为能够方便地传输或保存的格式时,串行化可能就是一种选择。
查看本文来源