//============================================================================== // 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="txhak@163.com"/> // <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 KevinShanLib { #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; 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 }