NET Framework提供了将对象序列化和反序列化的能力。利用这种机制,我们可以将对象实例的状态存储到存储媒体上,也可以将对象从一个地方传递到另一个地方。.NET Framework提供了一些用于序列化的类。一个是BinnaryFormatter,它使用二进制格式序列化对象。另一个是SoapFormatter,它使用soap格式(基于XML格式)序列化对象。还可以使用XMLSerializer将对象序列化成XML格式。然而这种序列化机制是有一定限制的,它只能序列化特定的对象。这些对象要么是从MarshalByRefObject派生的对象,要么是标记为Serializable的简单类型对象。像System.Windows.Forms.Control这类复杂的对象就不能被支持。jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
今天我要介绍的是如何序列化System.Windows.Forms.Control这类复杂的对象。在介绍之前,我们先看看序列化和反序列化的流程。jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
分离出复杂的逻辑,最简单的逻辑只有两步,第一步-序列化过程:将内存中的对象数据用XML格式的数据表示。第二步-反序列化过程:构造一个新对象,并将XML格式表示的数据赋值给这个新的对象。这样,原始对象和新构造的对象会有同样的数据,即表示同一种状态。jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
经常使用VS2005,VS2008等IDE的开发人员,特别是做过Design Time开发的开发人员可能会注意到,这个过程其实和IDE自动生成控件代码的过程相似。jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
在使用IDE的过程中,我们在Design环境中给Form拖一个TextBox控件,IDE会在Design环境中创建一个TextBox控件,并生成相关C#或者VB等格式的代码。这个阶段叫设计时(DesignTime)。这个过程类似我们刚才讲到的第一步-序列化过程。而我们点击运行的时候,这些文本格式的代码又会被编译运行,根据编译的代码生成一个新TextBox控件在Form上显示。这个阶段叫运行时(RunTime)。这个过程就类似我们刚才讲到的第二步-反序列化过程。可以看出来,IDE在DesignTime下是将控件实例序化成C#或VB等代码。而在RunTime下是将代码编译运行,生成新的控件实例来保持DesignTime下设计的状态与RunTime下显示的状态一致。事实上,这也是序列化和反序列化的一种方式。jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
既然IDE的这个过程也是序列化和反序列化的方式,那么IDE是怎么实现复杂控件序列化和反序列化的呢?这可能需要另外一篇文章才能讲清楚,这里暂不研究。不过我们可以知道,IDE是有能力做这件事情的。我们也可以利用IDE的这种能力,来实现复杂控件的序列化和反序列化。jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
下面这段代码演示了如何利用IDE的这种能力序列化一个Object。jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
SaveObjectjÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
1        /// <summary>jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
2        ///  Saves the <see cref="Tbject"/> to the given stream.jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
3        /// </summary>jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
4        /// <param name="value">jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
5        ///  The <see cref="Tbject"/> will be serialized to save.jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
6        /// </param>jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
7        /// <param name="stream">jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
8        ///  The stream to which the <see cref="Tbject"/> will be serialized.jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
9        /// </param>jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
10        public static void SaveObject(object value, Stream stream)jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
11        {jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
12            if (stream == null)jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
13            {jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
14                throw new ArgumentNullException();jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
15            }jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
16jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
17            using (DesignSurface designSurface = new DesignSurface())jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
18            {jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
19                designSurface.BeginLoad(new DefaultCodeDomDesignerLoader());jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
20                ComponentSerializationService serializationService = designSurface.GetService(typeof(ComponentSerializationService)) as ComponentSerializationService;jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
21jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
22                SerializationStore store = serializationService.CreateStore();jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
23                serializationService.Serialize(store, value);jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
24                store.Save(stream);jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
25            }jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
26        }jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
27
jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
下面这段代码演示了如何利用IDE的这种能力反序列化一个Object。 jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
LoadObjectjÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
1        /// <summary>jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
2        ///  Loads a <see cref="Tbject"/> from the given stream.jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
3        /// </summary>jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
4        /// <param name="stream">jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
5        ///  The stream from which to load the <see cref="Tbject"/>.jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
6        ///  </param>jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
7        /// <returns>jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
8        ///  The loaded <see cref="T:Object"/>.jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
9        /// </returns>jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
10        public static object LoadObject(Stream stream)jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
11        {jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
12            if (stream == null)jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
13            {jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
14                throw new ArgumentNullException();jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
15            }jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
16jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
17            using (DesignSurface designSurface = new DesignSurface())jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
18            {jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
19                designSurface.BeginLoad(new DefaultCodeDomDesignerLoader());jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
20                ComponentSerializationService serializationService = designSurface.GetService(typeof(ComponentSerializationService)) as ComponentSerializationService;jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
21jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
22                SerializationStore store = serializationService.LoadStore(stream);jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
23                ICollection collection = serializationService.Deserialize(store);jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
24jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
25                foreach (IComponent associatedComponent in designSurface.ComponentContainer.Components)jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
26                {jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
27                    designSurface.ComponentContainer.Remove(associatedComponent);jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
28                }jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
29jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
30                IEnumerator enumerator = collection.GetEnumerator();jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
31                if (enumerator.MoveNext())jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
32                {jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
33                    return enumerator.Current;jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
34                }jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
35jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
36                return null;jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
37            }jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
38        }
jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã 
利用IDE的这种能力,我们还可以做很多事情,比如深度克隆控件。有时候,我们需要克隆一个复杂的控件,然而办法有限,要么使用反射枚举控件所有字段赋值,要么给所有属性一个一个赋值。而属性之间的依赖关系,引用类型的属性如何处理等都是难题。利用控件序列化和反序列化,可以轻松实现控件的克隆。再比如在RunTime下得到控件的C#,VB等代码,因为序列化的中间产物就是C#,VB等代码,所以利用这个机制很容易实现。jÃIªº|ÊHRÐwww.netcsharp.cnßÿ 5uÿ—ã