DesignerSerializationManager.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / Designer / Host / Serialization / DesignerSerializationManager.cs / 1 / DesignerSerializationManager.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.ComponentModel.Design.Serialization { 
 
    using System;
    using System.Collections; 
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.ComponentModel.Design.Serialization; 
    using System.Design;
    using System.Diagnostics; 
    using System.IO; 
    using System.Reflection;
    using System.Runtime.InteropServices; 
    using System.Runtime.Serialization;
    using System.Text;

    ///  
    /// 
    ///     This object is a complete implementation of IDesignerSerializationManager.  It can be used to 
    ///     begin the serialization / deserialization process for any serialization scheme that utilizes 
    ///     IDesignerSerializationManager.
    ///  
    public class DesignerSerializationManager : IDesignerSerializationManager {

        private IServiceProvider                provider;
        private ITypeResolutionService          typeResolver; 
        private bool                            searchedTypeResolver;
        private bool                            recycleInstances; 
        private bool                            validateRecycledTypes; 
        private bool                            preserveNames;
        private IContainer                      container; 
        private IDisposable                     session;
        private ResolveNameEventHandler         resolveNameEventHandler;
        private EventHandler                    serializationCompleteEventHandler;
        private EventHandler                    sessionCreatedEventHandler; 
        private EventHandler                    sessionDisposedEventHandler;
        private ArrayList                       designerSerializationProviders; 
        private Hashtable                       defaultProviderTable; 
        private Hashtable                       instancesByName;
        private Hashtable                       namesByInstance; 
        private Hashtable                       serializers;
        private ArrayList                       errorList;
        private ContextStack                    contextStack;
        private PropertyDescriptorCollection    properties; 
        private object                          propertyProvider;
 
        ///  
        /// 
        ///     Creates a new serialization manager. 
        /// 
        public DesignerSerializationManager() {
            this.preserveNames = true;
            this.validateRecycledTypes = true; 
        }
 
        ///  
        /// 
        ///     Creates a new serialization manager. 
        /// 
        public DesignerSerializationManager(IServiceProvider provider) {
            if (provider == null) {
                throw new ArgumentNullException("provider"); 
            }
            this.provider = provider; 
            this.preserveNames = true; 
            this.validateRecycledTypes = true;
        } 

        /// 
        /// 
        ///     Provides access to the container that components will 
        ///     be added to.  The default implementation searches
        ///     for IDesignerHost in the service provider and uses 
        ///     its container if it exists. 
        /// 
        public IContainer Container { 
            get {
                if (container == null) {
                    IDesignerHost host = GetService(typeof(IDesignerHost)) as IDesignerHost;
                    if (host != null) { 
                        container = host.Container;
                    } 
                } 
                return container;
            } 
            set {
                CheckNoSession();
                container = value;
            } 
        }
 
        ///  
        /// 
        ///     This retrieves the collection of errors that have 
        ///     been reported to the serialization manager.
        ///     Additionaly, new errors can be added to the list
        ///     by accessing this property.
        ///  
        public IList Errors {
            get { 
                CheckSession(); 
                if (errorList == null) {
                    errorList = new ArrayList(); 
                }
                return errorList;
            }
        } 

        ///  
        ///  
        ///     This property determines the behavior of the CreateInstance method.  If true, CreateInstance will
        ///     pass the given component name.  If false, CreateInstance will check for the presence 
        ///     of the given name in the container.  If it does not exist, it will use the given name.
        ///     If it does exist, it will pass a null value as the name of a component when adding
        ///     it to the container, thereby giving it a new name.
        ///     This second variation is useful for implementing a serializer that always duplicates objects, rather than 
        ///     assuming those objects do not exist.  Paste commands often use this type of serializer.
        ///     The default value of this property is true. 
        ///  
        public bool PreserveNames {
            get { 
                return preserveNames;
            }
            set {
                CheckNoSession(); 
                preserveNames = value;
            } 
        } 

        ///  
        /// 
        ///     This property returns the object that should be used to provide properties to the serialization manager's Propeties property.  This object's
        ///     public properties will be inspected and wrapped in new property descriptors that have a target object of the serialization manager.
        ///  
        public object PropertyProvider {
            get { 
                return propertyProvider; 
            }
            set { 
                if (propertyProvider != value) {
                    propertyProvider = value;
                    properties = null;
                } 
            }
        } 
 
        /// 
        ///  
        ///     This property determines the behavior of the CreateInstance method.  If false, CreateInstance will always create a new instance
        ///     of an object.  If true, CreateInstance will first search the nametable and container for an object of the same name.  If such
        ///     an object exists and is of the same type, CreateInstance will return the existing object instance.  This second variation is
        ///     useful for implemeting a serializer that applies serialization state to an existing set of objects, rather than always creating 
        ///     a new tree.  Undo often uses this type of serializer.
        ///     The default value of this property is false. 
        ///  
        public bool RecycleInstances {
            get { 
                return recycleInstances;
            }
            set {
                CheckNoSession(); 
                recycleInstances = value;
            } 
        } 

        ///  
        /// 
        ///     This property determines the behavior of the CreateInstance method and only applies if RecyleInstances is true.  If true, and
        ///     an existing instance is found for the given name, it will only be returned if the two types match.  If false, the instance
        ///     will be returned even if the two types do not match.  This is useful for "morphing" one type of object to another if they have 
        ///     similar properties but share no common parent or interface.
        ///     The default value of this property is true. 
        ///  
        public bool ValidateRecycledTypes {
            get { 
                return validateRecycledTypes;
            }
            set {
                CheckNoSession(); 
                validateRecycledTypes = value;
            } 
        } 

        ///  
        /// 
        ///     Event that is raised when a session is created.
        /// 
        public event EventHandler SessionCreated { 
            add {
                sessionCreatedEventHandler += value; 
            } 
            remove {
                sessionCreatedEventHandler -= value; 
            }
        }

        ///  
        /// 
        ///     Event that is raised when a session is disposed. 
        ///  
        public event EventHandler SessionDisposed {
            add { 
                sessionDisposedEventHandler += value;
            }
            remove {
                sessionDisposedEventHandler -= value; 
            }
        } 
 
        /// 
        ///     Used to verify that no session is active.  If there is, this method 
        ///     throws.
        /// 
        private void CheckNoSession() {
            if (session != null) { 
                throw new InvalidOperationException(SR.GetString(SR.SerializationManagerWithinSession));
            } 
        } 

        ///  
        ///     Used to verify that there is an open session.  If there isn't, this method
        ///     throws.
        /// 
        private void CheckSession() { 
            if (session == null) {
                throw new InvalidOperationException(SR.GetString(SR.SerializationManagerNoSession)); 
            } 
        }
 
        /// 
        /// 
        ///     Creates an instance of the specified type.  The default
        ///     implementation will create the object.  If the object implements 
        ///     IComponent and only requires an empty or IContainer style
        ///     constructor, this will search for IDesignerHost and create 
        ///     through the host.  Otherwise it will use reflection.  If 
        ///     addToContainer is true, this will add to the container
        ///     using this class's Conainer property, using the 
        ///     name provided if it is not null.
        /// 
        protected virtual object CreateInstance(Type type, ICollection arguments, string name, bool addToContainer) {
            object[] argArray = null; 

            if (arguments != null && arguments.Count > 0) { 
                argArray = new object[arguments.Count]; 
                arguments.CopyTo(argArray, 0);
            } 

            object instance = null;

            // If we have been asked to recycle instances, look in our nametable 
            // and container first for an object matching this name and type.  If
            // we find it, we will use it. 
            // 
            if (RecycleInstances && name != null) {
 
                if (instancesByName != null) {
                    instance = instancesByName[name];
                }
 
                if (instance == null && addToContainer && Container != null) {
                    instance = Container.Components[name]; 
                } 

                if (instance != null && ValidateRecycledTypes && instance.GetType() != type) { 

                    // We got an instance, but it is not of the correct type.  We
                    // don't allow this.
                    instance = null; 
                }
            } 
 
            // If the stars properly align, we will let the designer host create the component.
            // For this to happen, the following criteria must hold true: 
            //
            // 1.  The type must be a component.
            // 2.  addToContainer is true.
            // 3.  The type has a null ctor or an IContainer ctor. 
            // 4.  The host is available and its container matches our container.
            // 
            // The reason for this is that if we went through activator, 
            // and if the object already specified a constructor that took an IContainer, our
            // deserialization mechanism would equate the container to the designer host.  This 
            // is the correct thing to do, but it has the side effect of adding the compnent
            // to the designer host twice -- once with a default name, and a second time with
            // the name we provide.  This equates to a component rename, which isn't cheap,
            // so we don't want to do it when we load each and every component. 
            //
            if (instance == null && addToContainer && typeof(IComponent).IsAssignableFrom(type) && (argArray == null || argArray.Length == 0 ||( argArray.Length == 1 && argArray[0] == Container))) { 
                IDesignerHost host = GetService(typeof(IDesignerHost)) as IDesignerHost; 

                if (host != null && host.Container == Container) { 

                    bool ignoreName = false;

                    if (!PreserveNames && name != null) { 

                        // Check if this name exists in the container.  If so, 
                        // don't use it. 
                        //
                        if (Container.Components[name] != null) { 
                            ignoreName = true;
                        }
                    }
 
                    if (name == null || ignoreName) {
                        instance = host.CreateComponent(type); 
                    } 
                    else {
                        instance = host.CreateComponent(type, name); 
                    }
                }
            }
 
            // Default case, just create the component through reflection.
            // 
            if (instance == null) { 

                try { 
                    try {
                        // First, just try to create the object directly with the arguments.  generaly this
                        // should work.
                        // 
                        instance = TypeDescriptor.CreateInstance(provider, type, null, argArray);
                    } 
                    catch (MissingMethodException mmex) { 

                        // okay, the create failed because the argArray didn't match the types of ctors that 
                        // are available.  don't panic, we're tough.  we'll try to coerce the types to match
                        // the ctor.
                        //
                        Type[] types = new Type[argArray.Length]; 

                        // first, get the types of the arguments we've got. 
                        // 
                        for(int index = 0; index < argArray.Length; index++) {
                            if (argArray[index] != null) { 
                                types[index] = argArray[index].GetType();
                            }
                        }
 
                        object[] tempArgs = new object[argArray.Length];
 
                        // now, walk the public ctors looking for one to 
                        // invoke here with the arguments we have.
                        // 
                        foreach(ConstructorInfo ci in TypeDescriptor.GetReflectionType(type).GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance)) {
                            ParameterInfo[] pi = ci.GetParameters();

                            // obviously the count has to match 
                            //
                            if (pi != null && pi.Length == types.Length) { 
                                bool match = true; 

                                // now walk every type of argument and compare it to 
                                // the corresponding argument.  if it matches up exactly or is a derived type, great.
                                // otherwise, we'll try to use IConvertible to make it into the right thing.
                                //
                                for (int t = 0; t < types.Length; t++) { 
                                    if (types[t] == null || pi[t].ParameterType.IsAssignableFrom(types[t])) {
                                        tempArgs[t] = argArray[t]; 
                                        continue; 
                                    }
 
                                    if (argArray[t] is IConvertible) {
                                        try {
                                            // try the IConvertible route.  If it works, we'll call it a match
                                            // for this parameter and continue on. 
                                            //
                                            tempArgs[t] = ((IConvertible)argArray[t]).ToType(pi[t].ParameterType, null); 
                                            continue; 
                                        }
                                        catch (InvalidCastException) { 
                                        }
                                    }
                                    match = false;
                                    break; 
                                }
                                // all of the parameters were converted or matched, so try the creation again. 
                                // if that works, we're in the money. 
                                //
                                if (match) { 
                                    instance = TypeDescriptor.CreateInstance(provider, type, null, tempArgs);
                                    break;
                                }
                            } 
                        }
 
                        // we still failed...rethrow the original exception. 
                        //
                        if (instance == null) { 
                            throw mmex;
                        }
                    }
 
                }
                catch(MissingMethodException) { 
                    StringBuilder argTypes = new StringBuilder(); 
                    foreach (object o in argArray) {
                        if (argTypes.Length > 0) { 
                            argTypes.Append(", ");
                        }

                        if (o != null) { 
                            argTypes.Append(o.GetType().Name);
                        } 
                        else { 
                            argTypes.Append("null");
                        } 

                    }

                    Exception ex = new SerializationException(SR.GetString(SR.SerializationManagerNoMatchingCtor, type.FullName, argTypes.ToString())); 
                    ex.HelpLink = SR.SerializationManagerNoMatchingCtor;
 
                    throw ex; 
                }
 
                // Now, if we needed to add this to the container, do so .
                //
                if (addToContainer && instance is IComponent && Container != null) {
                    bool ignoreName = false; 

                    if (!PreserveNames && name != null) { 
 
                        // Check if this name exists in the container.  If so,
                        // don't use it. 
                        //
                        if (Container.Components[name] != null) {
                            ignoreName = true;
                        } 
                    }
 
                    if (name == null || ignoreName) { 
                        Container.Add((IComponent)instance);
                    } 
                    else {
                        Container.Add((IComponent)instance, name);
                    }
                } 
            }
 
            return instance; 
        }
 
        /// 
        /// 
        ///     Creates a new serialization session.  Most data within
        ///     the serialization manager is transient and only lives 
        ///     for the life of a serialization session.  When a session
        ///     is disposed, serialization is considered to be complete 
        ///     and this transient state is cleared.  This allows a 
        ///     single instance of a serialization manager to be used
        ///     to serialize multiple object trees.  Some state, including 
        ///     the service provider and any custom serialization providers
        ///     that were added to the serialization manager, span sessions.	
        /// 
        public IDisposable CreateSession() { 
            if (session != null) {
                throw new InvalidOperationException(SR.GetString(SR.SerializationManagerAreadyInSession)); 
            } 

            session = new SerializationSession(this); 
            OnSessionCreated(EventArgs.Empty);

            return session;
        } 

        ///  
        ///  
        ///     This retrieves the serializer for the given object type.
        ///     You can request what type of serializer you would like. 
        ///     It is possible for this method to return null if there
        ///     is no serializer of the requested type.
        /// 
        public object GetSerializer(Type objectType, Type serializerType) { 

            if (serializerType == null) { 
                throw new ArgumentNullException("serializerType"); 
            }
 
            object serializer = null;

            if (objectType != null) {
                if (serializers != null) { 
                    // I don't double hash here.  It will be a very rare day where
                    // multiple types of serializers will be used in the same scheme. 
                    // We still handle it, but we just don't cache. 
                    //
                    serializer = serializers[objectType]; 
                    if (serializer != null && !serializerType.IsAssignableFrom(serializer.GetType())) {
                        serializer = null;
                    }
                } 

                // Now actually look in the type's metadata. 
                // 
                if (serializer == null) {
                    AttributeCollection attributes = TypeDescriptor.GetAttributes(objectType); 
                    foreach(Attribute attr in attributes) {
                        if (attr is DesignerSerializerAttribute) {
                            DesignerSerializerAttribute da = (DesignerSerializerAttribute)attr;
                            string typeName = da.SerializerBaseTypeName; 

                            // This serializer must support the correct base type or we're not interested. 
                            // 
                            if (typeName != null) {
                                Type baseType = GetType(typeName); 

                                if (baseType == serializerType && da.SerializerTypeName != null && da.SerializerTypeName.Length > 0) {
                                    Type type = GetType(da.SerializerTypeName);
 
                                    Debug.Assert(type != null, "Type " + objectType.FullName + " has a serializer that we couldn't bind to: " + da.SerializerTypeName);
                                    if (type != null) { 
                                        serializer = Activator.CreateInstance(type, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.CreateInstance, null, null, null); 
                                        break;
                                    } 
                                }
                            }
                        }
                    } 
                    // And stash this little guy for later, but only if we're in a session.
                    // If we're outside of a session this should still be useable for resolving 
                    // serializers, but we don't cache them. 
                    //
                    if (serializer != null && session != null) 
                    {
                         if (serializers == null)
                         {
                             serializers = new Hashtable(); 
                         }
                         serializers[objectType] = serializer; 
                    } 

                } 
            }

 	
            // Check for a default serialization provider 
            //
            if (defaultProviderTable == null || !defaultProviderTable.ContainsKey(serializerType)) { 
                Type defaultSerializerType = null; 

                DefaultSerializationProviderAttribute a = (DefaultSerializationProviderAttribute)TypeDescriptor.GetAttributes(serializerType)[typeof(DefaultSerializationProviderAttribute)]; 
                if (a != null) {
                    defaultSerializerType = GetType(a.ProviderTypeName);
                    if (defaultSerializerType != null && typeof(IDesignerSerializationProvider).IsAssignableFrom(defaultSerializerType)) {
                        IDesignerSerializationProvider p = (IDesignerSerializationProvider)Activator.CreateInstance( 
                            defaultSerializerType,
                            BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.CreateInstance, 
                            null, null, null); 

                        ((IDesignerSerializationManager)this).AddSerializationProvider(p); 
                    }
                }

                if (defaultProviderTable == null) { 
                    defaultProviderTable = new Hashtable();
                } 
 
                defaultProviderTable[serializerType] = defaultSerializerType;
            } 

            // Designer serialization providers can override our metadata discovery.
            // We loop until we reach steady state.  This breaks order dependencies
            // by allowing all providers a chance to party on each other's serializers. 
            //
            if (designerSerializationProviders != null) { 
                bool continueLoop = true; 
                for(int i = 0; continueLoop && i < designerSerializationProviders.Count; i++) {
 
                    continueLoop = false;

                    foreach(IDesignerSerializationProvider provider in designerSerializationProviders) {
                        object newSerializer = provider.GetSerializer(this, serializer, objectType, serializerType); 
                        if (newSerializer != null) {
                            continueLoop = (serializer != newSerializer); 
                            serializer = newSerializer; 
                        }
                    } 
                }
            }

 

            return serializer; 
        } 

        ///  
        /// 
        ///     Provides access to the underlying IServiceProvider
        /// 
        protected virtual object GetService(Type serviceType) { 

            if (serviceType == typeof(IContainer)) { 
                return Container; 
            }
 
            if (provider != null) {
                return provider.GetService(serviceType);
            }
 
            return null;
        } 
 
        /// 
        ///  
        ///     Retrives the type for the given name using the type resolution
        ///     service, if available.
        /// 
        protected virtual Type GetType(string typeName) { 
            if (typeResolver == null && !searchedTypeResolver) {
                typeResolver = GetService(typeof(ITypeResolutionService)) as ITypeResolutionService; 
                searchedTypeResolver = true; 
            }
 
            if (typeResolver == null) {
                return Type.GetType(typeName);
            }
            else { 
                return typeResolver.GetType(typeName);
            } 
        } 

        ///  
        /// 
        ///     Event that is raised when a name needs to be resolved to an object instance..
        /// 
        protected virtual void OnResolveName(ResolveNameEventArgs e) { 
            if (resolveNameEventHandler != null) {
                resolveNameEventHandler(this, e); 
            } 
        }
 
        /// 
        /// 
        ///     Event that is raised when a session is created.
        ///  
        protected virtual void OnSessionCreated(EventArgs e) {
            if (sessionCreatedEventHandler != null) { 
                sessionCreatedEventHandler(this, e); 
            }
        } 

        /// 
        /// 
        ///     Event that is raised when a session is disposed. 
        /// 
        protected virtual void OnSessionDisposed(EventArgs e)  { 
 
            try {
                try { 
                    if (sessionDisposedEventHandler != null) {
                        sessionDisposedEventHandler(this, e);
                    }
                } 
                finally {
                    if (serializationCompleteEventHandler != null) { 
                        serializationCompleteEventHandler(this, EventArgs.Empty); 
                    }
                } 
            }
            finally {
                resolveNameEventHandler = null;
                serializationCompleteEventHandler = null; 
                instancesByName = null;
                namesByInstance = null; 
                serializers = null; 
                contextStack = null;
                errorList = null; 
                session = null;
            }
        }
 
        /// 
        ///  
        ///     This method takes a property that is owned by the 
        ///     given owner, and it wraps them in new property that
        ///     is owned by the serialization manager. 
        /// 
        private PropertyDescriptor WrapProperty(PropertyDescriptor property, object owner) {
            if (property == null) {
                throw new ArgumentNullException("property"); 
            }
            // owner can be null for static properties. 
            return new WrappedPropertyDescriptor(property, owner); 
        }
 
        /// 
        /// 
        ///     The Context property provides a user-defined storage area
        ///     implemented as a stack.  This storage area is a useful way 
        ///     to provide communication across serializers, as serialization
        ///     is a generally hierarchial process. 
        ///  
        ContextStack IDesignerSerializationManager.Context {
            get { 
                if (contextStack == null) {
                    CheckSession();
                    contextStack = new ContextStack();
                } 
                return contextStack;
            } 
        } 

        ///  
        /// 
        ///     The Properties property provides a set of custom properties
        ///     the serialization manager may surface.  The set of properties
        ///     exposed here is defined by the implementor of 
        ///     IDesignerSerializationManager.
        ///  
        PropertyDescriptorCollection IDesignerSerializationManager.Properties { 
            get {
                if (properties == null) { 

                    object propObject = PropertyProvider;
                    PropertyDescriptor[] propArray;
 
                    if (propObject == null) {
                        propArray = new PropertyDescriptor[0]; 
                    } 
                    else {
                        PropertyDescriptorCollection props = TypeDescriptor.GetProperties(propObject); 
                        propArray = new PropertyDescriptor[props.Count];
                        for (int i = 0; i < propArray.Length; i++) {
                            propArray[i] = WrapProperty(props[i], propObject);
                        } 

                    } 
                    properties = new PropertyDescriptorCollection(propArray); 
                }
                return properties; 
            }
        }

        ///  
        /// 
        ///     ResolveName event.  This event 
        ///     is raised when GetName is called, but the name is not found 
        ///     in the serialization manager's name table.  It provides a
        ///     way for a serializer to demand-create an object so the serializer 
        ///     does not have to order object creation by dependency.  This
        ///     delegate is cleared immediately after serialization or deserialization
        ///     is complete.
        ///  
        event ResolveNameEventHandler IDesignerSerializationManager.ResolveName {
            add { 
                CheckSession(); 
                resolveNameEventHandler += value;
            } 
            remove {
                resolveNameEventHandler -= value;
            }
        } 

        ///  
        ///  
        ///     This event is raised when serialization or deserialization
        ///     has been completed.  Generally, serialization code should 
        ///     be written to be stateless.  Should some sort of state
        ///     be necessary to maintain, a serializer can listen to
        ///     this event to know when that state should be cleared.
        ///     An example of this is if a serializer needs to write 
        ///     to another file, such as a resource file.  In this case
        ///     it would be inefficient to design the serializer 
        ///     to close the file when finished because serialization of 
        ///     an object graph generally requires several serializers.
        ///     The resource file would be opened and closed many times. 
        ///     Instead, the resource file could be accessed through
        ///     an object that listened to the SerializationComplete
        ///     event, and that object could close the resource file
        ///     at the end of serialization. 
        /// 
        event EventHandler IDesignerSerializationManager.SerializationComplete { 
            add { 
                CheckSession();
                serializationCompleteEventHandler += value; 
            }
            remove {
                serializationCompleteEventHandler -= value;
            } 
        }
 
        ///  
        /// 
        ///     This method adds a custom serialization provider to the 
        ///     serialization manager.  A custom serialization provider will
        ///     get the opportunity to return a serializer for a data type
        ///     before the serialization manager looks in the type's
        ///     metadata. 
        /// 
        void IDesignerSerializationManager.AddSerializationProvider(IDesignerSerializationProvider provider) { 
            if (designerSerializationProviders == null) { 
                designerSerializationProviders = new ArrayList();
            } 
            if (!designerSerializationProviders.Contains(provider)) {
                designerSerializationProviders.Add(provider);
            }
        } 

        ///  
        ///  
        ///     Creates an instance of the given type and adds it to a collection
        ///     of named instances.  Objects that implement IComponent will be 
        ///     added to the design time container if addToContainer is true.
        /// 
        object IDesignerSerializationManager.CreateInstance(Type type, ICollection arguments, string name, bool addToContainer) {
 
            CheckSession();
 
            // If we were given a name verify that the name doesn't 
            // already exist.  We do not verify uniqueness in our parent container
            // here because CreateInstance may modify the name for us.  If it 
            // didn't, the container itself will throw, so we're covered.
            //
            if (name != null) {
                if (instancesByName != null && instancesByName.ContainsKey(name)) { 
                    Exception ex = new SerializationException(SR.GetString(SR.SerializationManagerDuplicateComponentDecl, name));
                    ex.HelpLink = SR.SerializationManagerDuplicateComponentDecl; 
                    throw ex; 
                }
            } 

            object instance = CreateInstance(type, arguments, name, addToContainer);

            // If we have a name save it into our own nametable.  We 
            // do this even for objects that were added to the container, because
            // containers reserve the right to change the name in case of collision. 
            // Changing the name is fine, but it would be very difficult to map 
            // that to the rest of the serializers.  Instead, we keep the old
            // name in our local nametable so a serializer can ask for an object 
            // by the old name.  Because the old nametable is searched first, the
            // old name is preserved.  Note that this technique is ONLY valid
            // if RecycleInstances is false.  If it is true, we cannot store
            // in the old nametable because it would be possible to fetch 
            // the wrong value from the container. Consider a request for
            // "button1' that results in the creation of an object in the 
            // container called "button2" due to a collision.  If a request 
            // later came in for "button2", the wrong object would be returned
            // because RecycleInstances checks the container first.  So, it 
            // is only safe to store the local value if RecycleInstances is false.
            // When RecycleInstances is true if there was a collision the object
            // would have been returned, so there is no need to store locally.
            // 
            if (name != null                    // If we were given a name
                && (!(instance is IComponent)   // And it's not an icomponent 
                    || !RecycleInstances)) {    // Or it is an icomponent but recycle instances is turned off 

                if (instancesByName == null) { 
                    instancesByName = new Hashtable();
                    namesByInstance = new Hashtable(new ReferenceComparer());
                }
 
                instancesByName[name] = instance;
                namesByInstance[instance] = name; 
            } 

            return instance; 
        }

        /// 
        ///  
        ///     Retrieves an instance of a created object of the given name, or
        ///     null if that object does not exist. 
        ///  
        object IDesignerSerializationManager.GetInstance(string name) {
 
            object instance = null;

            if (name == null) {
                throw new ArgumentNullException("name"); 
            }
 
            CheckSession(); 

            // Check our local nametable first 
            //
            if (instancesByName != null) {
                instance = instancesByName[name];
            } 

            if (instance == null && PreserveNames && Container != null) { 
                instance = Container.Components[name]; 
            }
 
            if (instance == null) {
                ResolveNameEventArgs e = new ResolveNameEventArgs(name);
                OnResolveName(e);
                instance = e.Value; 
            }
 
            return instance; 
        }
 
        /// 
        /// 
        ///     Retrieves a name for the specified object, or null if the object
        ///     has no name. 
        /// 
        string IDesignerSerializationManager.GetName(object value) { 
            string name = null; 

            if (value == null) { 
                throw new ArgumentNullException("value");
            }

            CheckSession(); 

            // Check our local nametable first 
            // 
            if (namesByInstance != null) {
                name = (string)namesByInstance[value]; 
            }

            if (name == null && value is IComponent) {
                ISite site = ((IComponent)value).Site; 
                if (site != null) {
                    INestedSite nestedSite = site as INestedSite; 
                    if (nestedSite != null) { 
                        name = nestedSite.FullName;
                    } 
                    else {
                        name = site.Name;
                    }
                } 
            }
            return name; 
        } 

        ///  
        /// 
        ///     Retrieves a serializer of the requested type for the given
        ///     object type.
        ///  
        object IDesignerSerializationManager.GetSerializer(Type objectType, Type serializerType) {
            return GetSerializer(objectType, serializerType); 
        } 

        ///  
        /// 
        ///     Retrieves a type of the given name.
        /// 
        Type IDesignerSerializationManager.GetType(string typeName) { 

            CheckSession(); 
 
            Type t = null;
 
            while (t == null) {
                t = GetType(typeName);

                if (t == null && typeName != null && typeName.Length > 0) { 
                    int dotIndex = typeName.LastIndexOf('.');
                    if (dotIndex == -1 || dotIndex == typeName.Length - 1) { 
                        break; 
                    }
 
                    typeName = typeName.Substring(0, dotIndex) + "+" + typeName.Substring(dotIndex + 1, typeName.Length - dotIndex - 1);
                }
            }
 
            return t;
        } 
 
        /// 
        ///  
        ///     Removes a previously added serialization provider.
        /// 
        void IDesignerSerializationManager.RemoveSerializationProvider(IDesignerSerializationProvider provider) {
            if (designerSerializationProviders != null) { 
                designerSerializationProviders.Remove(provider);
            } 
        } 

        ///  
        /// 
        ///     Reports a non-fatal error in serialization.  The serialization
        ///     manager may implement a logging scheme to alert the caller
        ///     to all non-fatal errors at once.  If it doesn't, it should 
        ///     immediately throw in this method, which should abort
        ///     serialization. 
        ///     Serialization may continue after calling this function. 
        /// 
        void IDesignerSerializationManager.ReportError(object errorInformation) { 
            CheckSession();
            if (errorInformation != null) {
                Errors.Add(errorInformation);
            } 
        }
 
        internal ArrayList SerializationProviders { 
            get {
                return (designerSerializationProviders != null) ? designerSerializationProviders.Clone() as ArrayList : new ArrayList(); 
            }
        }

        ///  
        /// 
        ///     Provides a way to set the name of an existing object. 
        ///     This is useful when it is necessary to create an 
        ///     instance of an object without going through CreateInstance.
        ///     An exception will be thrown if you try to rename an existing 
        ///     object or if you try to give a new object a name that
        ///     is already taken.
        /// 
        void IDesignerSerializationManager.SetName(object instance, string name) { 

            CheckSession(); 
 
            if (instance == null) {
                throw new ArgumentNullException("instance"); 
            }

            if (name == null) {
                throw new ArgumentNullException("name"); 
            }
 
            if (instancesByName == null) { 
                instancesByName = new Hashtable();
                namesByInstance = new Hashtable(new ReferenceComparer()); 
            }

            if (instancesByName[name] != null) {
                throw new ArgumentException(SR.GetString(SR.SerializationManagerNameInUse, name)); 
            }
 
            if (namesByInstance[instance] != null) { 
                throw new ArgumentException(SR.GetString(SR.SerializationManagerObjectHasName, name, (string)namesByInstance[instance]));
            } 

            instancesByName[name] = instance;
            namesByInstance[instance] = name;
        } 

        ///  
        ///  
        ///     IServiceProvider implementation.
        ///  
        object IServiceProvider.GetService(Type serviceType) {
            return GetService(serviceType);
        }
 
        /// 
        ///     Session object that implements IDisposable. 
        ///  
        private sealed class SerializationSession : IDisposable {
            private DesignerSerializationManager serializationManager; 

            internal SerializationSession(DesignerSerializationManager serializationManager) {
                this.serializationManager = serializationManager;
            } 

            public void Dispose() { 
                serializationManager.OnSessionDisposed(EventArgs.Empty); 
            }
        } 

        /// 
        ///     A key comparer that can be passed to a hash table
        ///     to use object reference identity as the key comparision. 
        /// 
        private sealed class ReferenceComparer : IEqualityComparer { 
            bool IEqualityComparer.Equals(object x, object y) { 
                return object.ReferenceEquals(x, y);
            } 

            int IEqualityComparer.GetHashCode(object x) {
                if (x != null) {
                    return x.GetHashCode(); 
                }
                return 0; 
            } 
        }
 
        /// 
        ///     Wrapped property descriptor.  Takes the given property
        ///     and wraps it in a new one that can take the designer serialization
        ///     manager as a target. 
        /// 
        private sealed class WrappedPropertyDescriptor : PropertyDescriptor { 
 
            private object              target;
            private PropertyDescriptor  property; 

            internal WrappedPropertyDescriptor(PropertyDescriptor property, object target) : base(property.Name, null) {
                this.property = property;
                this.target = target; 
            }
 
            public override AttributeCollection Attributes { 
                get {
                    return property.Attributes; 
                }
            }

            public override Type ComponentType { 
                get {
                    return property.ComponentType; 
                } 
            }
 
            public override bool IsReadOnly {
                get {
                    return property.IsReadOnly;
                } 
            }
 
            public override Type PropertyType { 
                get {
                    return property.PropertyType; 
                }
            }

            public override bool CanResetValue(object component) { 
                return property.CanResetValue(target);
            } 
 
            public override object GetValue(object component) {
                return property.GetValue(target); 
            }

            public override void ResetValue(object component) {
                property.ResetValue(target); 
            }
 
            public override void SetValue(object component, object value) { 
                property.SetValue(target, value);
            } 

            public override bool ShouldSerializeValue(object component) {
                return property.ShouldSerializeValue(target);
            } 
        }
    } 
} 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK