转,序列化控件

如何序列化Control等复杂类型对象

.NET Framework提供了将对象序列化和反序列化的能力。利用这种机制,我们可以将对象实例的状态存储到存储媒体上,也可以将对象从一个地方传递到另一个地方。

.NET Framework提供了一些用于序列化的类。一个是BinnaryFormatter,它使用二进制格式序列化对象。另一个是SoapFormatter,它使用soap格式(基于XML格式)序列化对象。还可以使用XMLSerializer将对象序列化成XML格式。然而这种序列化机制是有一定限制的,它只能序列化特定的对象。这些对象要么是从MarshalByRefObject派生的对象,要么是标记为Serializable的简单类型对象。像System.Windows.Forms.Control这类复杂的对象就不能被支持。

今天我要介绍的是如何序列化System.Windows.Forms.Control这类复杂的对象。在介绍之前,我们先看看序列化和反序列化的流程。

序列化反序列化流程图

 

分离出复杂的逻辑,最简单的逻辑只有两步,第一步-序列化过程:将内存中的对象数据用XML格式的数据表示。第二步-反序列化过程:构造一个新对象,并将XML格式表示的数据赋值给这个新的对象。这样,原始对象和新构造的对象会有同样的数据,即表示同一种状态。

经常使用VS2005,VS2008等IDE的开发人员,特别是做过Design Time开发的开发人员可能会注意到,这个过程其实和IDE自动生成控件代码的过程相似。

IDE设计编译流程

在使用IDE的过程中,我们在Design环境中给Form拖一个TextBox控件,IDE会在Design环境中创建一个TextBox控件,并生成相关C#或者VB等格式的代码。这个阶段叫设计时(DesignTime)。这个过程类似我们刚才讲到的第一步-序列化过程。而我们点击运行的时候,这些文本格式的代码又会被编译运行,根据编译的代码生成一个新TextBox控件在Form上显示。这个阶段叫运行时(RunTime)。这个过程就类似我们刚才讲到的第二步-反序列化过程。可以看出来,IDE在DesignTime下是将控件实例序化成C#或VB等代码。而在RunTime下是将代码编译运行,生成新的控件实例来保持DesignTime下设计的状态与RunTime下显示的状态一致。事实上,这也是序列化和反序列化的一种方式。

既然IDE的这个过程也是序列化和反序列化的方式,那么IDE是怎么实现复杂控件序列化和反序列化的呢?这可能需要另外一篇文章才能讲清楚,这里暂不研究。不过我们可以知道,IDE是有能力做这件事情的。我们也可以利用IDE的这种能力,来实现复杂控件的序列化和反序列化。

下面这段代码演示了如何利用IDE的这种能力序列化一个Object。


1        /// <summary>
2        ///   Saves the <see cref="T:Object"/> to the given stream.
3        /// </summary>
4        /// <param name="value">
5        ///   The <see cref="T:Object"/> will be serialized to save.
6        /// </param>
7        /// <param name="stream">
8        ///   The stream to which the <see cref="T:Object"/> will be serialized.
9        /// </param>

10        public static void SaveObject(object value, Stream stream)
11        {
12            if (stream == null)
13            {
14                throw new ArgumentNullException();
15            }

16
17            using (DesignSurface designSurface = new DesignSurface())
18            {
19                designSurface.BeginLoad(new DefaultCodeDomDesignerLoader());
20                ComponentSerializationService serializationService = designSurface.GetService(typeof(ComponentSerializationService)) as ComponentSerializationService;
21
22                SerializationStore store = serializationService.CreateStore();
23                serializationService.Serialize(store, value);
24                store.Save(stream);
25            }

26        }

27

下面这段代码演示了如何利用IDE的这种能力反序列化一个Object。


1        /// <summary>
2        ///   Loads a <see cref="T:Object"/> from the given stream.
3        /// </summary>
4        /// <param name="stream">
5        ///   The stream from which to load the <see cref="T:Object"/>.
6        /// </param>
7        /// <returns>
8        ///   The loaded <see cref="T:Object"/>.
9        /// </returns>

10        public static object LoadObject(Stream stream)
11        {
12            if (stream == null)
13            {
14                throw new ArgumentNullException();
15            }

16
17            using (DesignSurface designSurface = new DesignSurface())
18            {
19                designSurface.BeginLoad(new DefaultCodeDomDesignerLoader());
20                ComponentSerializationService serializationService = designSurface.GetService(typeof(ComponentSerializationService)) as ComponentSerializationService;
21
22                SerializationStore store = serializationService.LoadStore(stream);
23                ICollection collection = serializationService.Deserialize(store);
24
25                foreach (IComponent associatedComponent in designSurface.ComponentContainer.Components)
26                {
27                    designSurface.ComponentContainer.Remove(associatedComponent);
28                }

29
30                IEnumerator enumerator = collection.GetEnumerator();
31                if (enumerator.MoveNext())
32                {
33                    return enumerator.Current;
34                }

35
36                return null;
37            }

38        }

利用IDE的这种能力,我们还可以做很多事情,比如深度克隆控件。有时候,我们需要克隆一个复杂的控件,然而办法有限,要么使用反射枚举控件所有字段赋值,要么给所有属性一个一个赋值。而属性之间的依赖关系,引用类型的属性如何处理等都是难题。利用控件序列化和反序列化,可以轻松实现控件的克隆。再比如在RunTime下得到控件的C#,VB等代码,因为序列化的中间产物就是C#,VB等代码,所以利用这个机制很容易实现。这些代码我写了一个类库,需要的可以和我联系。代码太多,在这里就不贴了。

posted on 2010-04-28 11:25  imbob  阅读(1989)  评论(5编辑  收藏  举报

导航