.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的过程中,我们在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。
//==============================================================================
// File Name : CodeDomSerializationHelper.cs
//
// Copyright (C) 2007 KevinShan. All rights reserved.
//==============================================================================
// <fileinformation>
// <summary>
// Define the CodeDomSerializationHelper to do some serialization works.
// </summary>
// <author name="Kevin Shan" mail=">
// <seealso ref=""/>
// </fileinformation>
// <history>
// <record date="20070528" author="Kevin Shan" revision="1.00.000">
// Create this file.
// </record>
// </history>
using System;
using System.Collections;
using System.ComponentModel.Design;
using System.ComponentModel.Design.Serialization;
using System.IO;
using System.Windows.Forms;
using System.ComponentModel;
using System.Reflection;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
namespace Test
{
#region The CodeDomSerializationHelper class
/// <summary>
/// Define the CodeDomSerializationHelper to do some serialization works.
/// </summary>
internal static class CodeDomSerializationHelper
{
#region Nested Types
#region The DefaultCodeDomDesignerLoader class
/// <summary>
/// Inherits from CodeDomDesignerLoader.
/// </summary>
private class DefaultCodeDomDesignerLoader : CodeDomDesignerLoader
{
#region Instance Data
/// <summary>
/// Save the data of code compilie unit.
/// </summary>
private CodeCompileUnit _codeCompileUnit;
#endregion
#region Properties
private CodeDomProvider _codeDomProvider;
/// <summary>
/// Gets the <see cref="P:System.ComponentModel.Design.Serialization.CodeDomDesignerLoader.CodeDomProvider"></see> this designer loader will use.
/// </summary>
/// <value></value>
/// <returns>
/// The <see cref="P:System.ComponentModel.Design.Serialization.CodeDomDesignerLoader.CodeDomProvider"></see> this designer loader will use
/// </returns>
protected override CodeDomProvider CodeDomProvider
{
get
{
if (this._codeDomProvider == null)
{
this._codeDomProvider = new Microsoft.CSharp.CSharpCodeProvider();
}
return this._codeDomProvider;
}
}
private ITypeResolutionService _typeResolutionService;
/// <summary>
/// Gets the type resolution service to be used with this designer loader.
/// </summary>
/// <value></value>
/// <returns>
/// An <see cref="T:System.ComponentModel.Design.ITypeResolutionService"></see> that the CodeDOM serializers will use when resolving types.
/// </returns>
protected override ITypeResolutionService TypeResolutionService
{
get
{
if (this._typeResolutionService == null)
{
this._typeResolutionService = new DefaultTypeResolutionService(this.LoaderHost);
}
return this._typeResolutionService;
}
}
#endregion
#region Methods
/// <summary>
/// Parses the text or other persistent storage and returns a <see cref="T:System.CodeDom.CodeCompileUnit"></see>.
/// </summary>
/// <returns>
/// A <see cref="T:System.CodeDom.CodeCompileUnit"></see> resulting from a parse operation.
/// </returns>
protected override System.CodeDom.CodeCompileUnit Parse()
{
CodeTypeDeclaration designedClass = new CodeTypeDeclaration("AutoGeneratedClass");
designedClass.BaseTypes.Add(typeof(Form));
CodeNamespace nameSpace = new CodeNamespace("GrapeCity.AutoGeneratedCode");
nameSpace.Types.Add(designedClass);
CodeCompileUnit codeCompileUnit = new CodeCompileUnit();
codeCompileUnit.Namespaces.Add(nameSpace);
return codeCompileUnit;
}
/// <summary>
/// Writes compile-unit changes to persistent storage.
/// </summary>
/// <param name="unit">
/// The <see cref="T:System.CodeDom.CodeCompileUnit"></see> to be persisted.
/// </param>
protected override void Write(System.CodeDom.CodeCompileUnit unit)
{
this._codeCompileUnit = unit;
}
/// <summary>
/// Generates the source code.
/// </summary>
/// <returns></returns>
public string GenerateCode()
{
return this.GenerateCode(null);
}
/// <summary>
/// Generates the source code.
/// </summary>
/// <param name="codeDomProvider">
/// A <see cref="CodeDomProvider"/> indicates the code DOM provider.
/// </param>
/// <returns>
/// A <b>string</b> value indicates the source code.
/// </returns>
public string GenerateCode(CodeDomProvider codeDomProvider)
{
this.Flush();
if (this._codeCompileUnit != null)
{
CodeGeneratorOptions options = new CodeGeneratorOptions();
options.BracingStyle = "C";
using (StringWriter sw = new StringWriter())
{
if (codeDomProvider == null)
{
this.CodeDomProvider.GenerateCodeFromCompileUnit(this._codeCompileUnit, sw, options);
}
else
{
codeDomProvider.GenerateCodeFromCompileUnit(this._codeCompileUnit, sw, options);
}
return sw.ToString();
}
}
return string.Empty;
}
#endregion
}
#endregion
#region The DefaultTypeResolutionService class
/// <summary>
/// This service resolved the types and is required when using the CodeDomHostLoader.
/// </summary>
private class DefaultTypeResolutionService : ITypeResolutionService
{
#region Instance Data
/// <summary>
/// A <see cref="IDesignerLoaderHost"/> value indicates the designer loader host.
/// </summary>
private IDesignerLoaderHost _designerLoaderHost;
/// <summary>
/// A type cache pool to cache the finded type.
/// </summary>
private Dictionary<string, Type> _typeCachePool = new Dictionary<string, Type>();
#endregion
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="DefaultTypeResolutionService"/> class.
/// </summary>
/// <param name="designerLoaderHost">
/// A <see cref="IDesignerLoaderHost"/> value indicates the designer loader host.
/// </param>
public DefaultTypeResolutionService(IDesignerLoaderHost designerLoaderHost)
{
if (designerLoaderHost == null)
{
throw new ArgumentNullException();
}
this._designerLoaderHost = designerLoaderHost;
}
#endregion
#region ITypeResolutionService Members
/// <summary>
/// Gets the requested assembly.
/// </summary>
/// <param name="name">
/// The name of the assembly to retrieve.
/// </param>
/// <param name="throwOnError">
/// true if this method should throw an exception if the assembly cannot be located;
/// otherwise, false, and this method returns null if the assembly cannot be located.
/// </param>
/// <returns>
/// An instance of the requested assembly, or null if no assembly can be located.
/// </returns>
public Assembly GetAssembly(AssemblyName name, bool throwOnError)
{
throw new NotSupportedException();
}
/// <summary>
/// Gets the requested assembly.
/// </summary>
/// <param name="name">
/// The name of the assembly to retrieve.
/// </param>
/// <returns>
/// An instance of the requested assembly, or null if no assembly can be located.
/// </returns>
public Assembly GetAssembly(AssemblyName name)
{
throw new NotSupportedException();
}
/// <summary>
/// Gets the path to the file from which the assembly was loaded.
/// </summary>
/// <param name="name">
/// The name of the assembly.
/// </param>
/// <returns>
/// The path to the file from which the assembly was loaded.
/// </returns>
public string GetPathOfAssembly(AssemblyName name)
{
throw new NotSupportedException();
}
/// <summary>
/// Loads a type with the specified name.
/// </summary>
/// <param name="name">
/// The name of the type. If the type name is not a fully qualified name that indicates an assembly,
/// this service will search its internal set of referenced assemblies.
/// </param>
/// <param name="throwOnError">
/// true if this method should throw an exception if the assembly cannot be located;
/// otherwise, false, and this method returns null if the assembly cannot be located.
/// </param>
/// <param name="ignoreCase">
/// true to ignore case when searching for types; otherwise, false.
/// </param>
/// <returns>
/// An instance of <see cref="T:System.Type"></see> that corresponds to the specified name,
/// or null if no type can be found.
/// </returns>
public Type GetType(string name, bool throwOnError, bool ignoreCase)
{
Type returnType;
// 0, Search the type from the type cache pool.
if (this._typeCachePool.TryGetValue(name, out returnType))
{
return returnType;
}
// 1, Search the type use the Type.GetType method.
returnType = Type.GetType(name, false, ignoreCase);
if (returnType != null)
{
this._typeCachePool.Add(name, returnType);
return returnType;
}
Dictionary<Assembly, string> componentAssemblysCache = new Dictionary<Assembly, string>();
// 2, Search the type in root component's assembly.
if (this._designerLoaderHost.RootComponent != null)
{
Assembly assembly = this._designerLoaderHost.RootComponent.GetType().Assembly;
componentAssemblysCache.Add(assembly, assembly.FullName);
returnType = this.GetType(assembly, name, false, ignoreCase);
if (returnType != null)
{
this._typeCachePool.Add(name, returnType);
return returnType;
}
}
else
{
// Form is default root component
Assembly assembly = typeof(Form).Assembly;
componentAssemblysCache.Add(assembly, assembly.FullName);
returnType = this.GetType(assembly, name, false, ignoreCase);
if (returnType != null)
{
this._typeCachePool.Add(name, returnType);
return returnType;
}
}
// 3, Search the type in all components's assemblies which include in designer loader host's container.
if (this._designerLoaderHost.Container != null)
{
foreach (IComponent component in this._designerLoaderHost.Container.Components)
{
Assembly assembly = component.GetType().Assembly;
if (!componentAssemblysCache.ContainsKey(assembly))
{
componentAssemblysCache.Add(assembly, assembly.FullName);
returnType = this.GetType(assembly, name, false, ignoreCase);
if (returnType != null)
{
this._typeCachePool.Add(name, returnType);
return returnType;
}
}
}
}
// 4, Search the type in all components'a referenced assemblies.
List<Assembly> componentAssemblys = new List<Assembly>(componentAssemblysCache.Keys);
foreach (Assembly assembly in componentAssemblys)
{
AssemblyName[] assemblyNames = assembly.GetReferencedAssemblies();
foreach (AssemblyName assemblyName in assemblyNames)
{
if (!componentAssemblysCache.ContainsValue(assemblyName.FullName))
{
Assembly newAssembly = Assembly.Load(assemblyName);
if (!componentAssemblysCache.ContainsKey(newAssembly))
{
componentAssemblysCache.Add(newAssembly, newAssembly.FullName);
returnType = this.GetType(newAssembly, name, false, ignoreCase);
if (returnType != null)
{
this._typeCachePool.Add(name, returnType);
return returnType;
}
}
}
}
}
// 5, Search the type in current domain's assemblies.
Assembly[] assemblys = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblys)
{
if (!componentAssemblysCache.ContainsKey(assembly))
{
componentAssemblysCache.Add(assembly, assembly.FullName);
returnType = this.GetType(assembly, name, false, ignoreCase);
if (returnType != null)
{
this._typeCachePool.Add(name, returnType);
return returnType;
}
}
}
if (throwOnError)
{
throw new ArgumentException();
}
return null;
}
/// <summary>
/// Loads a type with the specified name in a specified assembly.
/// </summary>
/// <param name="assembly">
/// The indicates assembly.
/// </param>
/// <param name="name">
/// The name of the type. If the type name is not a fully qualified name that indicates an assembly,
/// this service will search its internal set of referenced assemblies.
/// </param>
/// <param name="throwOnError">
/// true if this method should throw an exception if the assembly cannot be located;
/// otherwise, false, and this method returns null if the assembly cannot be located.
/// </param>
/// <param name="ignoreCase">
/// true to ignore case when searching for types; otherwise, false.
/// </param>
/// <returns>
/// An instance of <see cref="T:System.Type"></see> that corresponds to the specified name,
/// or null if no type can be found.
/// </returns>
private Type GetType(Assembly assembly, string name, bool throwOnError, bool ignoreCase)
{
System.Diagnostics.Debug.Assert(assembly != null);
System.Diagnostics.Debug.Assert(!string.IsNullOrEmpty(name));
Type returnType = assembly.GetType(name, false, ignoreCase);
if (returnType == null)
{
int length = name.IndexOf(",");
if (length != -1)
{
string shortName = name.Substring(0, length);
returnType = assembly.GetType(shortName, false, ignoreCase);
}
}
if (returnType != null)
{
return returnType;
}
if (throwOnError)
{
throw new ArgumentException();
}
return null;
}
/// <summary>
/// Loads a type with the specified name.
/// </summary>
/// <param name="name">
/// The name of the type. If the type name is not a fully qualified name that indicates an assembly,
/// this service will search its internal set of referenced assemblies.
/// </param>
/// <param name="throwOnError">
/// true if this method should throw an exception if the assembly cannot be located;
/// otherwise, false, and this method returns null if the assembly cannot be located.
/// </param>
/// <returns>
/// An instance of <see cref="T:System.Type"></see> that corresponds to the specified name,
/// or null if no type can be found.
/// </returns>
public Type GetType(string name, bool throwOnError)
{
return this.GetType(name, throwOnError, false);
}
/// <summary>
/// Loads a type with the specified name.
/// </summary>
/// <param name="name">
/// The name of the type. If the type name is not a fully qualified name that indicates an assembly,
/// this service will search its internal set of referenced assemblies.
/// </param>
/// <returns>
/// An instance of <see cref="T:System.Type"></see> that corresponds to the specified name,
/// or null if no type can be found.
/// </returns>
public Type GetType(string name)
{
return this.GetType(name, true);
}
/// <summary>
/// Adds a reference to the specified assembly.
/// </summary>
/// <param name="name">
/// An <see cref="T:System.Reflection.AssemblyName"></see> that indicates the assembly to reference.
/// </param>
public void ReferenceAssembly(System.Reflection.AssemblyName name)
{
throw new NotSupportedException();
}
#endregion
}
#endregion
#region The DefaultTypeDescriptorFilterService class
/// <summary>
/// Provides a TypeDescriptorFilterService to remove the InheritanceAttribute.
/// </summary>
private class DefaultTypeDescriptorFilterService : ITypeDescriptorFilterService
{
#region Instance Data
/// <summary>
/// Save the old ITypeDescriptorFilterService.
/// </summary>
private ITypeDescriptorFilterService _oldService = null;
/// <summary>
/// The root component will filter the InheritanceAttribute.
/// </summary>
private IComponent _rootComponent = null;
#endregion
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="DefaultTypeDescriptorFilterService"/> class.
/// </summary>
/// <param name="oldService">The old service.</param>
/// <param name="rootComponent">The root component.</param>
public DefaultTypeDescriptorFilterService(ITypeDescriptorFilterService oldService, IComponent rootComponent)
{
this._oldService = oldService;
this._rootComponent = rootComponent;
}
#endregion
#region ITypeDescriptorFilterService Members
/// <summary>
/// Filters the attributes that a component exposes through a <see cref="T:System.ComponentModel.TypeDescriptor"/>.
/// </summary>
/// <param name="component">
/// The component to filter the attributes of.
/// </param>
/// <param name="attributes">
/// A dictionary of attributes that can be modified.
/// </param>
/// <returns>
/// true if the set of filtered attributes is to be cached; false if the filter service must query again.
/// </returns>
public bool FilterAttributes(IComponent component, IDictionary attributes)
{
bool result = true;
if (this._oldService != null)
{
result = this._oldService.FilterAttributes(component, attributes);
}
if (attributes != null)
{
if (this._rootComponent == null || this._rootComponent == component)
{
attributes.Remove(InheritanceAttribute.Default.TypeId);
}
}
return result;
}
/// <summary>
/// Filters the events that a component exposes through a <see cref="T:System.ComponentModel.TypeDescriptor"/>.
/// </summary>
/// <param name="component">
/// The component to filter events for.
/// </param>
/// <param name="events">
/// A dictionary of events that can be modified.
/// </param>
/// <returns>
/// true if the set of filtered events is to be cached; false if the filter service must query again.
/// </returns>
public bool FilterEvents(IComponent component, IDictionary events)
{
if (this._oldService != null)
{
return this._oldService.FilterEvents(component, events);
}
return true;
}
/// <summary>
/// Filters the properties that a component exposes through a <see cref="T:System.ComponentModel.TypeDescriptor"/>.
/// </summary>
/// <param name="component">
/// The component to filter properties for.
/// </param>
/// <param name="properties">
/// A dictionary of properties that can be modified.
/// </param>
/// <returns>
/// true if the set of filtered properties is to be cached; false if the filter service must query again.
/// </returns>
public bool FilterProperties(IComponent component, IDictionary properties)
{
if (this._oldService != null)
{
return this._oldService.FilterProperties(component, properties);
}
return true;
}
#endregion
}
#endregion
#endregion
/// <summary>
/// Clones a new instance of <see cref="T:IComponent"/> from the source <see cref="T:IComponent"/>.
/// </summary>
/// <param name="component">
/// The source <see cref="T:IComponent"/> will be clone.
/// </param>
/// <returns>
/// A new instance of <see cref="T:IComponent"/>.
/// </returns>
public static IComponent CloneComponent(IComponent component)
{
if (component == null)
{
throw new ArgumentNullException();
}
//
// Replace the old DescriptorFilterService with the new DefaultTypeDescriptorFilterService.
// The new DefaultTypeDescriptorFilterService will filter the InheritanceAttribute.
//
IServiceContainer serviceContainer = null;
ITypeDescriptorFilterService oldDescriptorFilterService = null;
if (component.Site != null)
{
serviceContainer = (IServiceContainer)component.Site.GetService(typeof(IServiceContainer));
if (serviceContainer != null)
{
oldDescriptorFilterService = serviceContainer.GetService(typeof(ITypeDescriptorFilterService)) as ITypeDescriptorFilterService;
if (oldDescriptorFilterService != null)
{
serviceContainer.RemoveService(typeof(ITypeDescriptorFilterService));
}
serviceContainer.AddService(typeof(ITypeDescriptorFilterService), new DefaultTypeDescriptorFilterService(oldDescriptorFilterService, component));
}
}
IComponent clonedComponent = CloneObject(component) as IComponent;
//
// Restore the DescriptorFilterService.
//
if (serviceContainer != null)
{
serviceContainer.RemoveService(typeof(ITypeDescriptorFilterService));
if (oldDescriptorFilterService != null)
{
serviceContainer.AddService(typeof(ITypeDescriptorFilterService), oldDescriptorFilterService);
}
}
return clonedComponent;
}
/// <summary>
/// Loads a <see cref="T:IComponent"/> from the given stream.
/// </summary>
/// <param name="stream">
/// The stream from which to load the <see cref="T:IComponent"/>.
/// </param>
/// <returns>
/// The loaded <see cref="T:IComponent"/>.
/// </returns>
public static IComponent LoadComponent(Stream stream)
{
return LoadObject(stream) as IComponent;
}
/// <summary>
/// Saves the <see cref="T:IComponent"/> to the given stream.
/// </summary>
/// <param name="component">
/// The <see cref="T:IComponent"/> will be serialized to save.
/// </param>
/// <param name="stream">
/// The stream to which the <see cref="T:IComponent"/> will be serialized.
/// </param>
public static void SaveComponent(IComponent component, Stream stream)
{
if (component == null)
{
throw new ArgumentNullException();
}
//
// Replace the old DescriptorFilterService with the new DefaultTypeDescriptorFilterService.
// The new DefaultTypeDescriptorFilterService will filter the InheritanceAttribute.
//
IServiceContainer serviceContainer = null;
ITypeDescriptorFilterService oldDescriptorFilterService = null;
if (component.Site != null)
{
serviceContainer = (IServiceContainer)component.Site.GetService(typeof(IServiceContainer));
if (serviceContainer != null)
{
oldDescriptorFilterService = serviceContainer.GetService(typeof(ITypeDescriptorFilterService)) as ITypeDescriptorFilterService;
if (oldDescriptorFilterService != null)
{
serviceContainer.RemoveService(typeof(ITypeDescriptorFilterService));
}
serviceContainer.AddService(typeof(ITypeDescriptorFilterService), new DefaultTypeDescriptorFilterService(oldDescriptorFilterService, component));
}
}
SaveObject(component, stream);
//
// Restore the DescriptorFilterService.
//
if (serviceContainer != null)
{
serviceContainer.RemoveService(typeof(ITypeDescriptorFilterService));
if (oldDescriptorFilterService != null)
{
serviceContainer.AddService(typeof(ITypeDescriptorFilterService), oldDescriptorFilterService);
}
}
}
/// <summary>
/// Clones a new instance of <see cref="T:Object"/> from the source <see cref="T:Object"/>.
/// </summary>
/// <param name="value">
/// The source <see cref="T:Object"/> will be clone.
/// </param>
/// <returns>
/// A new instance of <see cref="T:Object"/>.
/// </returns>
public static object CloneObject(object value)
{
using (DesignSurface designSurface = new DesignSurface())
{
designSurface.BeginLoad(new DefaultCodeDomDesignerLoader());
ComponentSerializationService serializationService = designSurface.GetService(typeof(ComponentSerializationService)) as ComponentSerializationService;
SerializationStore store = serializationService.CreateStore();
serializationService.Serialize(store, value);
store.Close();
ICollection collection = serializationService.Deserialize(store);
foreach (IComponent associatedComponent in designSurface.ComponentContainer.Components)
{
designSurface.ComponentContainer.Remove(associatedComponent);
}
IEnumerator enumerator = collection.GetEnumerator();
if (enumerator.MoveNext())
{
return enumerator.Current;
}
return null;
}
}
/// <summary>
/// Loads a <see cref="T:Object"/> from the given stream.
/// </summary>
/// <param name="stream">
/// The stream from which to load the <see cref="T:Object"/>.
/// </param>
/// <returns>
/// The loaded <see cref="T:Object"/>.
/// </returns>
public static object LoadObject(Stream stream)
{
if (stream == null)
{
throw new ArgumentNullException();
}
using (DesignSurface designSurface = new DesignSurface())
{
designSurface.BeginLoad(new DefaultCodeDomDesignerLoader());
ComponentSerializationService serializationService = designSurface.GetService(typeof(ComponentSerializationService)) as ComponentSerializationService;
stream.Position = 0;
SerializationStore store = serializationService.LoadStore(stream);
ICollection collection = serializationService.Deserialize(store);
foreach (IComponent associatedComponent in designSurface.ComponentContainer.Components)
{
designSurface.ComponentContainer.Remove(associatedComponent);
}
IEnumerator enumerator = collection.GetEnumerator();
if (enumerator.MoveNext())
{
return enumerator.Current;
}
return null;
}
}
/// <summary>
/// Saves the <see cref="T:Object"/> to the given stream.
/// </summary>
/// <param name="value">
/// The <see cref="T:Object"/> will be serialized to save.
/// </param>
/// <param name="stream">
/// The stream to which the <see cref="T:Object"/> will be serialized.
/// </param>
public static void SaveObject(object value, Stream stream)
{
if (stream == null)
{
throw new ArgumentNullException();
}
using (DesignSurface designSurface = new DesignSurface())
{
designSurface.BeginLoad(new DefaultCodeDomDesignerLoader());
ComponentSerializationService serializationService = designSurface.GetService(typeof(ComponentSerializationService)) as ComponentSerializationService;
SerializationStore store = serializationService.CreateStore();
serializationService.Serialize(store, value);
store.Save(stream);
}
}
/// <summary>
/// Gets the source code of the <see cref="T:IComponent"/>.
/// </summary>
/// <param name="component">
/// The source <see cref="T:IComponent"/> will get code.
/// </param>
/// <returns>
/// A <b>string value indicates the source code.</b>
/// </returns>
public static string GetCode(IComponent component)
{
return GetCode(component, null);
}
/// <summary>
/// Gets the source code of the <see cref="T:IComponent"/>.
/// </summary>
/// <param name="component">
/// The source <see cref="T:IComponent"/> will get code.
/// </param>
/// <param name="codeDomProvider">
/// A <see cref="CodeDomProvider"/> indicates the code DOM provider.
/// </param>
/// <returns>
/// A <b>string value indicates the source code.</b>
/// </returns>
public static string GetCode(IComponent component, CodeDomProvider codeDomProvider)
{
if (component == null)
{
throw new ArgumentNullException();
}
using (DesignSurface designSurface = new DesignSurface())
{
DefaultCodeDomDesignerLoader loader = new DefaultCodeDomDesignerLoader();
designSurface.BeginLoad(loader);
ComponentSerializationService serializationService = designSurface.GetService(typeof(ComponentSerializationService)) as ComponentSerializationService;
designSurface.ComponentContainer.Add(component);
string code = loader.GenerateCode(codeDomProvider);
designSurface.ComponentContainer.Remove(component);
return code;
}
}
}
#endregion
}