今天,抽空完成下序列化的学习。主要是通过阅读Jeffrey Cichter的《CLR Via C#》。2012-04-10
CLR via C# 之运行时序列化
Serialize Quick Start
我们通过一段代码来开始我们的学习之旅。
1 using System; 2 using System.Collections.Generic; 3 using System.IO; 4 using System.Linq; 5 using System.Runtime.Serialization.Formatters.Binary; 6 using System.Text; 7 8 namespace SerializeQuickStart 9 { 10 class Program 11 { 12 static void Main(string[] args) 13 { 14 var objectGraph = new List<String> { "Name1", "Name2", "Name3" }; 15 Stream stream = SerializeToMemory(objectGraph); 16 stream.Position = 0; 17 objectGraph = null; 18 19 objectGraph = (List<String>)DeserializeFromMemory(stream); 20 foreach (var name in objectGraph) 21 { 22 Console.WriteLine(name); 23 } 24 } 25 26 private static Stream SerializeToMemory(object objectGraph) 27 { 28 MemoryStream memoryStream = new MemoryStream(); 29 BinaryFormatter formatter = new BinaryFormatter(); 30 formatter.Serialize(memoryStream, objectGraph); 31 return memoryStream; 32 } 33 34 private static object DeserializeFromMemory(Stream stream) 35 { 36 BinaryFormatter formatter = new BinaryFormatter(); 37 return formatter.Deserialize(stream); 38 } 39 } 40 }
看完上面一段代码,我们会觉得序列化其实也很简单。SerializeToMemory方法构造了System.IO.MemoryStream对象。我们把序列化好的字节块放到内存流对象中。然后方法通过BinaryFormatter对象的实例,序列化传入的对象。FCL(Framework Class Library)提供了两个格式化器:BinaryFomatter和SoapFomatter。想要序列化一个对象,只需要使用格式化器中的Serialize和Deserialize方法就可以达到目的了。
从上面一段代码中,我们需要注意几点。其一,序列化和反序列化的格式化器要一致。其二,当序列化时,确保流的位置被置为0。其三,我们可以将多个对象序列化到同一个流中。(序列化对象的顺序与反序列化的顺序必须一致,比方说你序列化的顺序为A,B,C,你反序列化的顺序也应该为A,B,C。)其四,最重要的一项,序列化一个对象的时候,类型的全名和类型的定义程序集的名称会被写入流。有的扩展程序使用Assembly.LoadFrom加载一个程序集,然后根据加载的程序集中定义的类型来构造对象。这些对象可以毫无问题地序列化到流中。然而,反序列化流时,格式化器会通过调用Assembly的Load方法来尝试加载程序集。在书中,Jeffrey Richter建议实现一个方法,方法签名匹配System.ResolveEventHandler(Deserialze方法返回结果后,马上向事件注销这个方法。)这个方法用来防止反序列化中可能找不到程序集。
Make Class Serializable
当我们定义一个类时,默认是不可序列化的。如何让一个自定义的类能够被序列化呢?很简单,为这个类打上SerializableAttribute,这个定制attribute只能应用于类型(class)、值类型(struct)、枚举值(enum)和委托类型(delegate)。注意,枚举和委托总是可序列化的。
Control Serialize
我们需要控制序列化,如果字段含有反序列化后变得无效的信息,或者字段容易被计算得到。这些字段,建议打上NonSerializedAttribute定制attribute来指定类型中哪些字段不应序列化。
1 using System; 2 using System.Collections.Generic; 3 using System.IO; 4 using System.Linq; 5 using System.Runtime.Serialization; 6 using System.Runtime.Serialization.Formatters.Binary; 7 using System.Text; 8 9 namespace ControlSerializtion 10 { 11 internal class Program 12 { 13 static void Main(string[] args) 14 { 15 Circle circle = new Circle(10); 16 MemoryStream memoryStream = new MemoryStream(); 17 BinaryFormatter formatter = new BinaryFormatter(); 18 formatter.Serialize(memoryStream, circle); 19 memoryStream.Position = 0; 20 circle = null; 21 circle = (Circle)formatter.Deserialize(memoryStream); 22 Console.WriteLine(circle.Area); 23 } 24 } 25 26 [Serializable] 27 internal class Circle 28 { 29 private Double m_radius; 30 31 [NonSerialized] 32 private Double m_area; 33 34 public Circle(Double radius) 35 { 36 m_radius = radius; 37 m_area = Math.PI * m_radius * m_radius; 38 } 39 40 [OnDeserialized] 41 private void OnDeserialized(StreamingContext context) 42 { 43 m_area = Math.PI * m_radius * m_radius; 44 } 45 46 public Double Area { get { return m_area; } } 47 } 48 }
下节更精彩,讲解格式化器是如何序列化类型的实例的。^.^ 2012-04-10