序列化(serialization)是将一个对象或者对象图转换成字节流的过程。反序列化(deserialization)是将一个字节流转换会对象的过程。在对象和字节流之间转换时非常有用的机制。下面是一些例子:
应用程序的状态(对象图)可以保存到磁盘文件或数据库,并在应用程序下次运行时恢复。如asp.net就是利用它来保持和恢复会话状态的。
一个对象可以轻松复制到系统的剪贴板,在粘贴会同一个或另一个应用程序。windows窗体和wpf就是利用这个功能。
一组对象可以可以轻松的通过网络发给另一台机器上运行的进程。Microsoft .net framework的Remoting架构会对按值封送的对象进行序列化和反序列化。这个技术还可以跨越AppDomain边界发送对象。
除了上述应用,一旦将对象序列化为内存中的一个字节流,可以使用一些更有用的方式来方便的处理数据,比如加密和压缩数据等。
24.1 序列化/反序列化快速入门
返回
复制代码
1 using System.IO;
2 using System.Reflection;
3 using System.Runtime.Serialization;
4 using System.Runtime.Serialization.Formatters.Binary;
5
6 internal static class QuickStart {
7 public static void Go() {
8 // Create a graph of objects to serialize them to the stream
9 var objectGraph = new List { “Jeff”, “Kristin”, “Aidan”, “Grant” };
10 Stream stream = SerializeToMemory(objectGraph);
11
12 // Reset everything for this demo
13 stream.Position = 0;
14 objectGraph = null;
15
16 // Deserialize the objects and prove it worked
17 objectGraph = (List)DeserializeFromMemory(stream);
18 foreach (var s in objectGraph) Console.WriteLine(s);
19 }
20
21 private static MemoryStream SerializeToMemory(Object objectGraph) {
22 // Construct a stream that is to hold the serialized objects
23 MemoryStream stream = new MemoryStream();
24
25 // Construct a serialization formatter that does all the hard work
26 BinaryFormatter formatter = new BinaryFormatter();
27
28 // Tell the formatter to serialize the objects into the stream
29 formatter.Serialize(stream, objectGraph);
30
31 // Return the stream of serialized objects back to the caller
32 return stream;
33 }
34
35 private static Object DeserializeFromMemory(Stream stream) {
36 // Construct a serialization formatter that does all the hard work
37 BinaryFormatter formatter = new BinaryFormatter();
38
39 // Tell the formatter to deserialize the objects from the stream
40 return formatter.Deserialize(stream);
41 }
42 }
复制代码
FCL提供了两个格式化器:Binaryformatter和SoapFormatter。要序列化一个对象图,只需调用格式化器的Serialize方法 。方法原型如下:
1 public void Serialize(Stream serializationStream, object graph);
格式化器调用Serialize方法是,为了确保对象图中所有对象都被序列化到流中,格式器会参考每个类型的元数据。序列化时,利用反射来查看每个对象类型中有哪些实例字段,这些实例字段中,又有哪些引用了其他对象,然后对他们进行序列化。
序列化是应注意:
1)使用相同的格式化器进行序列化和反序列化。
2)序列化一个对象时,类型的全名和类型定义的程序集名称会被写入流。在反序列化是,会用这些信息,会用System.Reflection.Assembly.Load方法加载程序集,再在程序集中找到匹配的类型,找到后创建类型的实例,并用流中的值对其字段进行初始化。
24.2 使类型可序列化
返回
FCL得内置类型或者说基元类型已经标识的特性[Serializable],使得他们可序列化。
使类型可序列化语法很简单,只需在类上标上特性[Serializable],它是在System命名空间中定义的。
SerializableAttribute这个特性只能应用于引用类型、值类型。除此之外,这个特性是不会被派生类继承的;反之,则不亦然因此System.Object标识了这个特性。
24.3 控制序列化和反序列化
返回
类标识上特性[Serializable]后,所有实例字段(public,private,protected)都会被序列化,有时我们不希望某些字段被实例化,如下情况:
字段之在当前进程内有效,如句柄。
字段含有很容易计算的信息
标识字段不需序列化也很简单,只需在字段前标上特性[NonSerializable]即可。注意:该特性不会被派生类继承。
但当一个字段没有序列化,会在反序列化化是出现问题,如某些方法用到这个字段,需要当前值,FCL提供了以下方法:
复制代码
1 [OnSerializing]
2 private void OnSerializing(StreamingContext context)
3 {//在序列化前,修改任何需要修改的状态 }
4 [OnSerialized]
5 private void OnSerialized(StreamingContext context)
6 {//在序列化后,恢复任何需要修改的状态 }
7
8 [OnDeserializing]
9 private void OnDeserializing(StreamingContext context)
10 {//在反序列化前,修改任何需要修改的状态 }
11 [OnDeserialized]
12 private void OnDeserialized(StreamingContext context)
13 {// 在反序列化后,恢复任何需要修改的状态}
复制代码