本节要深入讨论一下格式化器如何序列化对象的字段。掌握了这些知识后,可以更容易地理解本章后面要解释的一些更高级的序列化和反序列化技术。
为了简化格式化器的操作,FCL在System.Runtime.Serialization命名空间提供了一个FormatterServices类型。该类型只包含静态方法,而且该类型不能实例化。以下步骤描述了格式化器如何自动序列化一个应用了SerializableAttribute的对象。
- 格式化器调用FormatterServices的GetSerializableMembers方法:
public static MemberInfo[] GetSerializableMembers(Type type, StreamingContext context);
这个方法利用反射获取类型的public和private字段实例。方法返回由MemberInfo对象构成的一个数组,其中每个元素都对应于一个可序列化的实例字段。
- 对象被序列化,MemberInfo对象数组传给FormatterServices的静态方法GetObjectData,这个方法返回一个Object数组,其中每个元素都标识了被序列化的那个对象中的一个字段的值。这个Object数组和MemberInfo数组是并行的;换言之,Object数组中的元素0时MemberInfo数组中的元素0所标识的那个成员的值。
- 格式化器将程序集标识和类型的完整名称写入流中。
- 格式化器然后遍历这两个数组中的元素,将每个成员的名称和值写入流中。
以下步骤描述了格式化器如何自动反序列化一个应用了SerializableAttribute的对象。
- 格式化器从流中读取程序集和完整类型名称。如何程序集不能加载,就抛出一个SerializationException异常,对象不能反序列化。如果程序集已加载,格式化器将程序集标识信息和类型全名传给FormatterServices的静态方法GetTypeFromAssembly,这个方法返回一个System.Type对象,它代表要反序列化的那个对象的类型。
- 格式化器调用FormatterServices的静态方法GetUninitializedObject,
这个方法为一个对象分配内存,并不为对象调用构造函数。然后对象的所有字段都被初始化为成null或0.
- 格式化器现在构造并初始化一个MemberInfo数组,具体做法和前面的做法一样,都是调用FormatterServices的GetSerializableMembers方法。这个方法返回序列化好、现在需要反序列化的一组字段。
- 格式化器根据流中包含的数据创建并初始化一个Object数组。
- 将对新分配的对象、MemberInfo数组以及并行Object数组的引用传给FormatterServices的静态方法PopulateObjectMembers,这个方法遍历数组,将每个字段初始化成对应的值。到此为止,对象就算被彻底反序列化了。