CLR Via C# 3rd 阅读摘要 -- Chapter 24 – Runtime Serialization

Serialization/Deserialization Quick Start

  1. 序列化是将一个对象以及相关的对象转换成字节流的过程;反序列化就是序列化的逆过程;
  2. System.Runtime.Serialization命名空间;
  3. 当序列化一个对象时,Formatter首先抓取程序集标识,并确定程序集通过调用System.Reflection.Assembly.Load()被装载到执行的AppDomain中;
  4. 程序集被装载后,Formatter在程序集中查找待反序列化对象所匹配的类型,然后实例化再根据流来初始化实例的字段;
  5. 一些扩展程序使用Assembly.LoadFrom()来加载程序集,然后从定义在程序集中的类型来构造对象。这些对象在序列化时没有问题,但是反序列化时,Formatter会尝试使用Assembly.Load()来加载程序集,大多数情况下,CLR不能准确定位程序集文件,所以可能会引发SerializationException;
  6. 因为上面的原因,如果使用Assembly.LoadFrom()来加载程序集,那么强烈建议在反序列化之前处理System.AppDomain.AssemblyResolver事件。

Making a Type Serializable

  1. 对象在默认情况下是不能序列化的,可以通过给类型加上[Serializable]标签来实现;
  2. [Serializable]属性不能被子类型所继承;
  3. System.Object有[Serializable]属性;
  4. 一般来说,推荐大多数类型为可序列化的?(我的看法是那些可能会被跨边界访问的类型)。

Controlling Serialization and Deserialization

  1. 至少有两个原因使得你不打算让类型实例的一些字段被序列化:
    • 字段的值在反序列化时已经失效了,比如Windows Kernel对象的句柄(文件、进程、线程、互斥体、事件、信号量、……);
    • 字段的值可以在反序列化时很简单的重新计算出来。
  2. 字段加上[NonSerialized]属性标签可以阻止该字段被序列化;
  3. 如果希望字段在反序列化时被重新计算,可以定义一个方法[OnDeserialized]private void OnDeserialized(StreamingContext context){...}
  4. 跟[OnDeserialized]相似的几个属性[OnSerializing] -> [OnSerialized] -> [OnDeserializing] -> [OnDeserialized];
  5. 如果你序列化一个类型的实例,在类型中加入新的字段,然后在尝试反序列化时,Formatter会抛出SerializationException指出成员数目不对,可以通过使用[OptionalField]属性标签来解决该问题。

How Formatters Serialize Type Instances

  1. FormatterServices.GetSerializableMembers(), .GetObjectData(), GetTypeFromAssembly(), GetUninitializedObject(), .PopulateObjectMembers()静态方法。

Controlling the Serialized/Deserialized Data

  1. 如何完全的控制序列化/反序列化,可以实现System.Runtime.Serialization.ISerializable接口;
  2. 一旦类型继承了ISerializable接口,那么子类型也就必须实现该接口;
  3. 建议在GetObjectData方法和特殊构造器上附加[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]属性标签;
  4. 当Formatter在序列化对象图时,先查找每一个对象,如果有一个类型实现了ISerializable接口,Formatter就忽略其他所有的客户属性,并构造一个新的System.Runtime.Serialization.SerializationInfo对象;
  5. 总是调用SerializationInfo.AddValue来加入序列化信息到类型中,如果字段的类型实现了ISerializable接口,别在字段上调用GetObjectData,而是调用AddValue;
  6. 如果类型是sealed,那么强烈建议将特殊构造声明为private;
  7. 如果基类没有实现ISerializable接口,怎样为类型实现该接口?FormatterServices.GetSerializableMembers()。

Streaming Contexts

  1. StreamingContext.State, .Context;
  2. StreamingContextStates {CrossProcess, CrossMachines, File, Persistence, Remoting, Other, Clone, CrossAppDomain, All};

Serializing a Type as a Different Type and Deserializing an Object as a Different Object

Serialization Surrogates

  1. System.Runtime.Serialization.ISerializationSurrogate.GetObjectData(), .SetObjectData();
  2. BinaryFormatter有一个bug阻止从序列化对象到其他的引用。要解决该问题,需要传一个ISerializationSurrogate对象的引用到FormatterServices.GetSurrogateForCyclicalReference()方法;
  3. SurrogateSelector.AddSurrogate(),多个SurrogateSelector对象可以被链接起来,SurrogateSelector实现了ISurrogateSelector接口。

Overriding the Assembly and/or Type When Deserializing an Object

  1. System.Runtime.Serialization.SerializationBinder使得反序列化对象到不同的类型非常容易。要做到这点,需要定义的类型继承自抽象类SerializationBinder。

本章小结

   本章讲了序列化和反序列化的知识,序列化可以讲对象转换成流进行传输或者持久化,在需要的时候通过反序列化在将对象构造出来。首先讲了如何让类型具备序列化的能力,以及如何控制序列化的过程。然后讲了Formatter如何序列化类型实例,如何控制序列化/反序列化的数据,介绍了StreamingContext对象,演示了如何将对象反序列化到不同的类型实例。接着介绍了序列化代理,最后讲了SerializationBinder抽象类可以用来反序列化对象到不同的类型。

posted @ 2010-05-31 15:14 bengxia 阅读(...) 评论(...) 编辑 收藏
无觅相关文章插件,快速提升流量