TypeDescriptor.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / CompMod / System / ComponentModel / TypeDescriptor.cs / 1 / TypeDescriptor.cs

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

/* 
 */ 
namespace System.ComponentModel
{ 
    using System.Runtime.Serialization.Formatters;
    using System.Threading;
    using System.Runtime.Remoting.Activation;
    using System.Runtime.InteropServices; 
    using System.Diagnostics;
    using System; 
    using CodeAccessPermission = System.Security.CodeAccessPermission; 
    using System.Security.Permissions;
    using System.Collections; 
    using System.Globalization;
    using System.IO;
    using System.Reflection;
    using Microsoft.Win32; 
    using System.ComponentModel.Design;
    using System.Diagnostics.CodeAnalysis; 
    using System.Runtime.Versioning; 

    ///  
    ///    Provides information about the properties and events
    ///    for a component. This class cannot be inherited.
    /// 
    [HostProtection(SharedState = true)] 
    public sealed class TypeDescriptor
    { 
        // Note: this is initialized at class load because we 
        // lock on it for thread safety.  It is used from nearly
        // every call to this class, so it will be created soon after 
        // class load anyway.
        private static WeakHashtable _providerTable     = new WeakHashtable();  // mapping of type or object hash to a provider list
        private static Hashtable     _providerTypeTable = new Hashtable();      // A direct mapping from type to provider.
        private static Hashtable     _defaultProviders  = new Hashtable();      // A table of type -> default provider to track DefaultTypeDescriptionProviderAttributes. 
        private static WeakHashtable _associationTable;
        private static int           _metadataVersion;                          // a version stamp for our metadata.  Used by property descriptors to know when to rebuild 
                                                                                // attributes. 

 
        // This is an index that we use to create a unique name for a property in the
        // event of a name collision.  The only time we should use this is when
        // a name collision happened on an extender property that has no site or
        // no name on its site.  Should be very rare. 
        private static int _collisionIndex;
 
        // events 
        private static RefreshEventHandler _refreshHandler;
 
        private static BooleanSwitch TraceDescriptor = new BooleanSwitch("TypeDescriptor", "Debug TypeDescriptor.");

        #if DEBUG
        private static BooleanSwitch EnableValidation = new BooleanSwitch("EnableValidation", "Enable type descriptor Whidbey->RTM validation"); 
        #endif
 
        // For each stage of our filtering pipeline, the pipeline needs to know 
        // what it is filtering.
        private const int PIPELINE_ATTRIBUTES = 0x00; 
        private const int PIPELINE_PROPERTIES = 0x01;
        private const int PIPELINE_EVENTS = 0x02;

        // And each stage of the pipeline needs to have its own 
        // keys for its cache table.  We use guids because they
        // are unique and fast to compare.  The order for each of 
        // these keys must match the Id's of the filter type above. 
        private static readonly Guid[] _pipelineInitializeKeys = new Guid[]
        { 
            Guid.NewGuid(), // attributes
            Guid.NewGuid(), // properties
            Guid.NewGuid()  // events
        }; 

        private static readonly Guid[] _pipelineMergeKeys = new Guid[] 
        { 
            Guid.NewGuid(), // attributes
            Guid.NewGuid(), // properties 
            Guid.NewGuid()  // events
        };

        private static readonly Guid[] _pipelineFilterKeys = new Guid[] 
        {
            Guid.NewGuid(), // attributes 
            Guid.NewGuid(), // properties 
            Guid.NewGuid()  // events
        }; 

        private static readonly Guid[] _pipelineAttributeFilterKeys = new Guid[]
        {
            Guid.NewGuid(), // attributes 
            Guid.NewGuid(), // properties
            Guid.NewGuid()  // events 
        }; 

        private static object _internalSyncObject = new object(); 

        private TypeDescriptor()
        {
        } 

        ///  
        ///  
        /// 
        [Obsolete("This property has been deprecated.  Use a type description provider to supply type information for COM types instead.  http://go.microsoft.com/fwlink/?linkid=14202")] 
        public static IComNativeDescriptorHandler ComNativeDescriptorHandler
        {
            [PermissionSetAttribute(SecurityAction.LinkDemand, Name="FullTrust")]
            get 
            {
                TypeDescriptionNode node = NodeFor(ComObjectType); 
                ComNativeDescriptionProvider provider = null; 

                do 
                {
                    provider = node.Provider as ComNativeDescriptionProvider;
                    node = node.Next;
                } 
                while(node != null && provider == null);
 
                if (provider != null) 
                {
                    return provider.Handler; 
                }

                return null;
            } 
            [PermissionSetAttribute(SecurityAction.LinkDemand, Name="FullTrust")]
            set 
            { 
                TypeDescriptionNode node = NodeFor(ComObjectType);
 
                while (node != null && !(node.Provider is ComNativeDescriptionProvider))
                {
                    node = node.Next;
                } 

                if (node == null) 
                { 
                    AddProvider(new ComNativeDescriptionProvider(value), ComObjectType);
                } 
                else
                {
                    ComNativeDescriptionProvider provider = (ComNativeDescriptionProvider)node.Provider;
                    provider.Handler = value; 
                }
            } 
        } 

 
        /// 
        ///     This property returns a Type object that can be passed to the various
        ///     AddProvider methods to define a type description provider for COM types.
        ///  
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static Type ComObjectType 
        { 
            get
            { 
                return typeof(TypeDescriptorComObject);
            }
        }
 
        /// 
        ///     This value increments each time someone refreshes or changes metadata. 
        ///  
        internal static int MetadataVersion {
            get { 
                return _metadataVersion;
            }
        }
 
        /// 
        ///  
        ///    Occurs when Refreshed is raised for a component. 
        /// 
        public static event RefreshEventHandler Refreshed 
        {
            add
            {
                _refreshHandler += value; 
            }
            remove 
            { 
                _refreshHandler -= value;
            } 
        }

        /// 
        ///     The AddAttributes method allows you to add class-level attributes for a 
        ///     type or an instance.  This method simply implements a type description provider
        ///     that merges the provided attributes with the attributes that already exist on 
        ///     the class.  This is a short cut for such a behavior.  Adding additional 
        ///     attributes is common need for applications using the Windows Forms property
        ///     window.  The return value form AddAttributes is the TypeDescriptionProvider 
        ///     that was used to add the attributes.  This provider can later be passed to
        ///     RemoveProvider if the added attributes are no longer needed.
        /// 
        [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")] 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static TypeDescriptionProvider AddAttributes(Type type, params Attribute[] attributes) { 
 
            if (type == null) {
                throw new ArgumentNullException("type"); 
            }

            if (attributes == null) {
                throw new ArgumentNullException("attributes"); 
            }
 
            TypeDescriptionProvider existingProvider = GetProvider(type); 
            TypeDescriptionProvider provider = new AttributeProvider(existingProvider, attributes);
            TypeDescriptor.AddProvider(provider, type); 
            return provider;
        }

        ///  
        ///     The AddAttributes method allows you to add class-level attributes for a
        ///     type or an instance.  This method simply implements a type description provider 
        ///     that merges the provided attributes with the attributes that already exist on 
        ///     the class.  This is a short cut for such a behavior.  Adding additional
        ///     attributes is common need for applications using the Windows Forms property 
        ///     window.  The return value form AddAttributes is the TypeDescriptionProvider
        ///     that was used to add the attributes.  This provider can later be passed to
        ///     RemoveProvider if the added attributes are no longer needed.
        ///  
        [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        public static TypeDescriptionProvider AddAttributes(object instance, params Attribute[] attributes) { 

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

            if (attributes == null) { 
                throw new ArgumentNullException("attributes");
            } 
 
            TypeDescriptionProvider existingProvider = GetProvider(instance);
            TypeDescriptionProvider provider = new AttributeProvider(existingProvider, attributes); 
            TypeDescriptor.AddProvider(provider, instance);
            return provider;
        }
 
        /// 
        ///  
        ///     Adds an editor table for the given editor base type. 
        ///     ypically, editors are specified as metadata on an object. If no metadata for a
        ///     equested editor base type can be found on an object, however, the 
        ///     ypeDescriptor will search an editor
        ///     able for the editor type, if one can be found.
        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        public static void AddEditorTable(Type editorBaseType, Hashtable table)
        { 
            ReflectTypeDescriptionProvider.AddEditorTable(editorBaseType, table); 
        }
 
        /// 
        ///     Adds a type description provider that will be called on to provide
        ///     type and instance information for any object that is of, or a subtype
        ///     of, the provided type.  Type can be any type, including interfaces. 
        ///     For example, to provide custom type and instance information for all
        ///     components, you would pass typeof(IComponent).  Passing typeof(object) 
        ///     will cause the provider to be called to provide type information for 
        ///     all types.
        ///  
        [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static void AddProvider(TypeDescriptionProvider provider, Type type)
        { 
            if (provider == null)
            { 
                throw new ArgumentNullException("provider"); 
            }
 
            if (type == null)
            {
                throw new ArgumentNullException("type");
            } 

            lock(_providerTable) 
            { 
                // Get the root node, hook it up, and stuff it back into
                // the provider cache. 
                TypeDescriptionNode node = NodeFor(type, true);
                TypeDescriptionNode head = new TypeDescriptionNode(provider);
                head.Next = node;
                _providerTable[type] = head; 
                _providerTypeTable.Clear();
            } 
 
            Refresh(type);
        } 

        /// 
        ///     Adds a type description provider that will be called on to provide
        ///     type information for a single object instance.  A provider added 
        ///     using this method will never have its CreateInstance method called
        ///     because the instance already exists.  This method does not prevent 
        ///     the object from finalizing. 
        /// 
        [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")] 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static void AddProvider(TypeDescriptionProvider provider, object instance)
        {
            if (provider == null) 
            {
                throw new ArgumentNullException("provider"); 
            } 

            if (instance == null) 
            {
                throw new ArgumentNullException("instance");
            }
 
            // Get the root node, hook it up, and stuff it back into
            // the provider cache. 
            lock(_providerTable) 
            {
                TypeDescriptionNode node = NodeFor(instance, true); 
                TypeDescriptionNode head = new TypeDescriptionNode(provider);
                head.Next = node;
                _providerTable.SetWeak(instance, head);
                _providerTypeTable.Clear(); 
            }
 
            Refresh(instance); 
        }
 
        /// 
        ///     This method verifies that we have checked for the presence
        ///     of a default type description provider attribute for the
        ///     given type. 
        /// 
        //See security note below 
        [SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts")] 
        private static void CheckDefaultProvider(Type type)
        { 
            if (_defaultProviders == null)
            {
                lock (_internalSyncObject)
                { 
                    if (_defaultProviders == null)
                    { 
                        _defaultProviders = new Hashtable(); 
                    }
                } 
            }

            if (_defaultProviders.ContainsKey(type))
            { 
                return;
            } 
 
            lock (_internalSyncObject)
            { 
                if (_defaultProviders.ContainsKey(type))
                {
                    return;
                } 

                // Immediately clear this.  If we find a default provider 
                // and it starts messing around with type information, 
                // this could infinitely recurse.
                // 
                _defaultProviders[type] = null;
            }

            // Always use core reflection when checking for 
            // the default provider attribute.  If there is a
            // provider, we probably don't want to build up our 
            // own cache state against the type.  There shouldn't be 
            // more than one of these, but walk anyway.  Walk in
            // reverse order so that the most derived takes precidence. 
            //
            object[] attrs = type.GetCustomAttributes(typeof(TypeDescriptionProviderAttribute), false);
            bool providerAdded = false;
            for (int idx = attrs.Length - 1; idx >= 0; idx--) 
            {
                TypeDescriptionProviderAttribute pa = (TypeDescriptionProviderAttribute)attrs[idx]; 
                Type providerType = Type.GetType(pa.TypeName); 
                if (providerType != null && typeof(TypeDescriptionProvider).IsAssignableFrom(providerType))
                { 
                    TypeDescriptionProvider prov;

                    // Security Note: TypeDescriptionProviders are similar to TypeConverters and UITypeEditors in the
                    // sense that they provide a public API while not necessarily being public themselves. As such, 
                    // we need to allow instantiation of internal TypeDescriptionProviders. See the thread attached
                    // to VSWhidbey #500522 for a more detailed discussion. 
                    IntSecurity.FullReflection.Assert(); 
                    try {
                        prov = (TypeDescriptionProvider)Activator.CreateInstance(providerType); 
                    }
                    finally {
                        CodeAccessPermission.RevertAssert();
                    } 
                    Trace("Providers : Default provider found : {0}", providerType.Name);
                    AddProvider(prov, type); 
                    providerAdded = true; 
                }
            } 

            // If we did not add a provider, check the base class.
            if (!providerAdded) {
                Type baseType = type.BaseType; 
                if (baseType != null && baseType != type) {
                    CheckDefaultProvider(baseType); 
                } 
            }
        } 

        /// 
        ///     The CreateAssocation method creates an association between two objects.
        ///     Once an association is created, a designer or other filtering mechanism 
        ///     can add properties that route to either object into the primary object's
        ///     property set.  When a property invocation is made against the primary 
        ///     object, GetAssocation will be called to resolve the actual object 
        ///     instance that is related to its type parameter.
        ///  
        [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static void CreateAssociation(object primary, object secondary)
        { 
            if (primary == null)
            { 
                throw new ArgumentNullException("primary"); 
            }
 
            if (secondary == null)
            {
                throw new ArgumentNullException("secondary");
            } 

            if (primary == secondary) 
            { 
                throw new ArgumentException(SR.GetString(SR.TypeDescriptorSameAssociation));
            } 

            if (_associationTable == null)
            {
                lock (_internalSyncObject) 
                {
                    if (_associationTable == null) 
                    { 
                        _associationTable = new WeakHashtable();
                    } 
                }
            }

            IList associations = (IList)_associationTable[primary]; 

            if (associations == null) 
            { 
                lock (_associationTable)
                { 
                    associations = (IList)_associationTable[primary];
                    if (associations == null)
                    {
                        associations = new ArrayList(4); 
                        _associationTable.SetWeak(primary, associations);
                    } 
                } 
            }
            else 
            {
                for (int idx = associations.Count - 1; idx >= 0; idx--)
                {
                    WeakReference r = (WeakReference)associations[idx]; 
                    if (r.IsAlive && r.Target == secondary)
                    { 
                        throw new ArgumentException(SR.GetString(SR.TypeDescriptorAlreadyAssociated)); 
                    }
                } 
            }

            lock(associations)
            { 
                associations.Add(new WeakReference(secondary));
            } 
        } 

        ///  
        ///     Creates an instance of the designer associated with the
        ///     specified component.
        /// 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2113:SecureLateBindingMethods")] 
        public static IDesigner CreateDesigner(IComponent component, Type designerBaseType)
        { 
            Type designerType = null; 
            IDesigner designer = null;
 
            // Get the set of attributes for this type
            //
            AttributeCollection attributes = GetAttributes(component);
 
            for (int i = 0; i < attributes.Count; i++)
            { 
                DesignerAttribute da = attributes[i] as DesignerAttribute; 
                if (da != null)
                { 
                    Type attributeBaseType = Type.GetType(da.DesignerBaseTypeName);
                    if (attributeBaseType != null && attributeBaseType == designerBaseType)
                    {
                        ISite site = component.Site; 
                        bool foundService = false;
 
                        if (site != null) 
                        {
                            ITypeResolutionService tr = (ITypeResolutionService)site.GetService(typeof(ITypeResolutionService)); 
                            if (tr != null)
                            {
                                foundService = true;
                                designerType = tr.GetType(da.DesignerTypeName); 
                            }
                        } 
 
                        if (!foundService)
                        { 
                            designerType = Type.GetType(da.DesignerTypeName);
                        }

                        Debug.Assert(designerType != null, "It may be okay for the designer not to load, but we failed to load designer for component of type '" + component.GetType().FullName + "' because designer of type '" + da.DesignerTypeName + "'"); 
                        if (designerType != null)
                        { 
                            break; 
                        }
                    } 
                }
            }

            if (designerType != null) 
            {
                designer = (IDesigner)SecurityUtils.SecureCreateInstance(designerType, null, true); 
            } 

            return designer; 
        }

        /// 
        ///     This dynamically binds an EventDescriptor to a type. 
        /// 
        [ReflectionPermission(SecurityAction.LinkDemand, Flags=ReflectionPermissionFlag.MemberAccess)] 
        public static EventDescriptor CreateEvent(Type componentType, string name, Type type, params Attribute[] attributes) 
        {
            return new ReflectEventDescriptor(componentType, name, type, attributes); 
        }

        /// 
        ///     This creates a new event descriptor identical to an existing event descriptor.  The new event descriptor 
        ///     has the specified metadata attributes merged with the existing metadata attributes.
        ///  
        [ReflectionPermission(SecurityAction.LinkDemand, Flags=ReflectionPermissionFlag.MemberAccess)] 
        public static EventDescriptor CreateEvent(Type componentType, EventDescriptor oldEventDescriptor, params Attribute[] attributes)
        { 
            return new ReflectEventDescriptor(componentType, oldEventDescriptor, attributes);
        }

        ///  
        ///     This method will search internal tables within TypeDescriptor for
        ///     a TypeDescriptionProvider object that is associated with the given 
        ///     data type.  If it finds one, it will delegate the call to that object. 
        /// 
        public static object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args) 
        {
            if (objectType == null)
            {
                throw new ArgumentNullException("objectType"); 
            }
 
            if (argTypes != null) 
            {
                if (args == null) 
                {
                    throw new ArgumentNullException("args");
                }
 
                if (argTypes.Length != args.Length)
                { 
                    throw new ArgumentException(SR.GetString(SR.TypeDescriptorArgsCountMismatch)); 
                }
            } 

            object instance = null;

            // See if the provider wants to offer a TypeDescriptionProvider to delegate to.  This allows 
            // a caller to have complete control over all object instantiation.
            if (provider != null) { 
                TypeDescriptionProvider p = provider.GetService(typeof(TypeDescriptionProvider)) as TypeDescriptionProvider; 
                if (p != null) {
                    instance = p.CreateInstance(provider, objectType, argTypes, args); 
                }
            }

            if (instance == null) { 
                instance = NodeFor(objectType).CreateInstance(provider, objectType, argTypes, args);
            } 
 
            return instance;
        } 

        /// 
        ///     This dynamically binds a PropertyDescriptor to a type.
        ///  
        [ReflectionPermission(SecurityAction.LinkDemand, Flags=ReflectionPermissionFlag.MemberAccess)]
        public static PropertyDescriptor CreateProperty(Type componentType, string name, Type type, params Attribute[] attributes) 
        { 
            return new ReflectPropertyDescriptor(componentType, name, type, attributes);
        } 

        /// 
        ///     This creates a new property descriptor identical to an existing property descriptor.  The new property descriptor
        ///     has the specified metadata attributes merged with the existing metadata attributes. 
        /// 
        [ReflectionPermission(SecurityAction.LinkDemand, Flags=ReflectionPermissionFlag.MemberAccess)] 
        public static PropertyDescriptor CreateProperty(Type componentType, PropertyDescriptor oldPropertyDescriptor, params Attribute[] attributes) 
        {
 
            // We must do some special case work here for extended properties.  If the old property descriptor is really
            // an extender property that is being surfaced on a component as a normal property, then we must
            // do work here or else ReflectPropertyDescriptor will fail to resolve the get and set methods.  We check
            // for the necessary ExtenderProvidedPropertyAttribute and if we find it, we create an 
            // ExtendedPropertyDescriptor instead.  We only do this if the component class is the same, since the user
            // may want to re-route the property to a different target. 
            // 
            if (componentType == oldPropertyDescriptor.ComponentType)
            { 
                ExtenderProvidedPropertyAttribute attr = (ExtenderProvidedPropertyAttribute)
                                                         oldPropertyDescriptor.Attributes[
                                                         typeof(ExtenderProvidedPropertyAttribute)];
 
                ReflectPropertyDescriptor reflectDesc = attr.ExtenderProperty as ReflectPropertyDescriptor;
                if (reflectDesc != null) 
                { 
                    return new ExtendedPropertyDescriptor(oldPropertyDescriptor, attributes);
                } 
                #if DEBUG
                else
                {
                    DebugReflectPropertyDescriptor debugReflectDesc = attr.ExtenderProperty as DebugReflectPropertyDescriptor; 
                    if (debugReflectDesc != null)
                    { 
                        return new DebugExtendedPropertyDescriptor(oldPropertyDescriptor, attributes); 
                    }
                } 
                #endif
            }

            // This is either a normal prop or the caller has changed target classes. 
            //
            return new ReflectPropertyDescriptor(componentType, oldPropertyDescriptor, attributes); 
        } 

        ///  
        ///     Debug code that runs the output of a TypeDescriptor query into a debug
        ///     type descriptor that uses the V1.0 algorithm.  This code will assert
        ///     if the two type descriptors do not agree.  This method returns true if
        ///     validation should be performed for the type. 
        /// 
        #if DEBUG 
        private static bool DebugShouldValidate(object key) 
        {
            // Check our switch first. 
            //
            if (EnableValidation.Enabled)
            {
                while(key != null) 
                {
                    // We only validate if there are no custom providers all the way 
                    // up the class chain. 
                    TypeDescriptionNode node = _providerTable[key] as TypeDescriptionNode;
                    if (node != null && !(node.Provider is ReflectTypeDescriptionProvider)) 
                    {
                        return false;
                    }
 
                    if (key is Type)
                    { 
                        key = ((Type)key).BaseType; 
                    }
                    else 
                    {
                        key = key.GetType();
                        if (((Type)key).IsCOMObject)
                        { 
                            key = ComObjectType;
                        } 
                    } 
                }
                return true; 
            }
            return false;
        }
        #endif 

        ///  
        ///     Debug code that runs the output of a TypeDescriptor query into a debug 
        ///     type descriptor that uses the V1.0 algorithm.  This code will assert
        ///     if the two type descriptors do not agree. 
        /// 
        [Conditional("DEBUG")]
        private static void DebugValidate(Type type, AttributeCollection attributes, AttributeCollection debugAttributes)
        { 
            #if DEBUG
            if (!DebugShouldValidate(type)) return; 
            DebugValidate(attributes, debugAttributes); 
            #endif
        } 

        /// 
        ///     Debug code that runs the output of a TypeDescriptor query into a debug
        ///     type descriptor that uses the V1.0 algorithm.  This code will assert 
        ///     if the two type descriptors do not agree.
        ///  
        [Conditional("DEBUG")] 
        private static void DebugValidate(AttributeCollection attributes, AttributeCollection debugAttributes)
        { 
            #if DEBUG

            if (attributes.Count >= debugAttributes.Count)
            { 
                foreach(Attribute a in attributes)
                { 
                    if (!(a is GuidAttribute) && !(a is ComVisibleAttribute)) 
                    {
                        bool found = false; 
                        bool typeFound = false;

                        // Many attributes don't implement .Equals correctly,
                        // so they will fail an equality check.  But we want to 
                        // make sure that common ones like Browsable and ReadOnly
                        // were correctly picked up.  So only check the ones in 
                        // component model. 
                        if (!a.GetType().FullName.StartsWith("System.Component"))
                        { 
                            found = true;
                            break;
                        }
 
                        if (!found)
                        { 
                            foreach(Attribute b in debugAttributes) 
                            {
                                if (!typeFound && a.GetType() == b.GetType()) 
                                {
                                    typeFound = true;
                                }
 
                                // Semitrust may throw here.
                                try 
                                { 
                                    if (a.Equals(b))
                                    { 
                                        found = true;
                                        break;
                                    }
                                } 
                                catch
                                { 
                                    found = true; 
                                    break;
                                } 
                            }
                        }

                        if (!found && !a.IsDefaultAttribute()) 
                        {
                            if (typeFound) 
                            { 
                                Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Attribute {0} was found but failed equality.  Perhaps attribute .Equals is not implemented correctly?", a.GetType().Name));
                            } 
                            else
                            {
                                Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Attribute {0} should not exist", a.GetType().Name));
                            } 
                        }
                    } 
                } 
            }
            else 
            {
                foreach(Attribute b in debugAttributes)
                {
                    // We skip all interop attributes because interface merging has changed on purpose. 
                    if (!(b is GuidAttribute) && !(b is ComVisibleAttribute) && !(b is InterfaceTypeAttribute) && !(b is ReadOnlyAttribute))
                    { 
                        bool found = false; 
                        bool typeFound = false;
 
                        // Many attributes don't implement .Equals correctly,
                        // so they will fail an equality check.  But we want to
                        // make sure that common ones like Browsable and ReadOnly
                        // were correctly picked up.  So only check the ones in 
                        // component model.
                        if (!b.GetType().FullName.StartsWith("System.Component")) 
                        { 
                            found = true;
                            break; 
                        }

                        if (!found)
                        { 
                            foreach(Attribute a in attributes)
                            { 
                                if (!typeFound && a.GetType() == b.GetType()) 
                                {
                                    typeFound = true; 
                                }

                                // Semitrust may throw here.
                                try 
                                {
                                    if (b.Equals(a)) 
                                    { 
                                        found = true;
                                        break; 
                                    }
                                }
                                catch
                                { 
                                    found = true;
                                    break; 
                                } 
                            }
                        } 

                        if (!found && !b.IsDefaultAttribute())
                        {
                            if (!typeFound) 
                            {
                                Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Attribute {0} should exist", b.GetType().Name)); 
                            } 
                        }
                    } 
                }
            }
#endif
        } 

        ///  
        ///     Debug code that runs the output of a TypeDescriptor query into a debug 
        ///     type descriptor that uses the V1.0 algorithm.  This code will assert
        ///     if the two type descriptors do not agree. 
        /// 
        [Conditional("DEBUG")]
        private static void DebugValidate(AttributeCollection attributes, Type type)
        { 
            #if DEBUG
            if (!DebugShouldValidate(type)) return; 
            AttributeCollection debugAttributes = DebugTypeDescriptor.GetAttributes(type); 
            DebugValidate(attributes, debugAttributes);
            #endif 
        }

        /// 
        ///     Debug code that runs the output of a TypeDescriptor query into a debug 
        ///     type descriptor that uses the V1.0 algorithm.  This code will assert
        ///     if the two type descriptors do not agree. 
        ///  
        [Conditional("DEBUG")]
        private static void DebugValidate(AttributeCollection attributes, object instance, bool noCustomTypeDesc) 
        {
            #if DEBUG
            if (!DebugShouldValidate(instance)) return;
            AttributeCollection debugAttributes = DebugTypeDescriptor.GetAttributes(instance, noCustomTypeDesc); 
            DebugValidate(attributes, debugAttributes);
            #endif 
        } 

        ///  
        ///     Debug code that runs the output of a TypeDescriptor query into a debug
        ///     type descriptor that uses the V1.0 algorithm.  This code will assert
        ///     if the two type descriptors do not agree.
        ///  
        [Conditional("DEBUG")]
        private static void DebugValidate(TypeConverter converter, Type type) 
        { 
            #if DEBUG
            if (!DebugShouldValidate(type)) return; 
            TypeConverter debugConverter = DebugTypeDescriptor.GetConverter(type);
            Debug.Assert(debugConverter.GetType() == converter.GetType(), "TypeDescriptor engine Validation Failure.");
            #endif
        } 

        ///  
        ///     Debug code that runs the output of a TypeDescriptor query into a debug 
        ///     type descriptor that uses the V1.0 algorithm.  This code will assert
        ///     if the two type descriptors do not agree. 
        /// 
        [Conditional("DEBUG")]
        private static void DebugValidate(TypeConverter converter, object instance, bool noCustomTypeDesc)
        { 
            #if DEBUG
            if (!DebugShouldValidate(instance)) return; 
            TypeConverter debugConverter = DebugTypeDescriptor.GetConverter(instance, noCustomTypeDesc); 
            Debug.Assert(debugConverter.GetType() == converter.GetType(), "TypeDescriptor engine Validation Failure.");
            #endif 
        }

        /// 
        ///     Debug code that runs the output of a TypeDescriptor query into a debug 
        ///     type descriptor that uses the V1.0 algorithm.  This code will assert
        ///     if the two type descriptors do not agree. 
        ///  
        [Conditional("DEBUG")]
        private static void DebugValidate(EventDescriptorCollection events, Type type, Attribute[] attributes) 
        {
            #if DEBUG
            if (!DebugShouldValidate(type)) return;
            EventDescriptorCollection debugEvents = DebugTypeDescriptor.GetEvents(type, attributes); 
            Debug.Assert(debugEvents.Count == events.Count, "TypeDescriptor engine Validation Failure. Event counts differ.");
            foreach(EventDescriptor debugEvt in debugEvents) 
            { 
                EventDescriptor evt = null;
 
                foreach(EventDescriptor realEvt in events)
                {
                    if (realEvt.Name.Equals(debugEvt.Name) && realEvt.EventType == debugEvt.EventType && realEvt.ComponentType == debugEvt.ComponentType)
                    { 
                        evt = realEvt;
                        break; 
                    } 
                }
 
                Debug.Assert(evt != null, "TypeDescriptor engine Validation Failure. Event " + debugEvt.Name + " does not exist or is of the wrong type.");
                if (evt != null)
                {
                    AttributeCollection attrs = evt.Attributes; 
                    if (attrs[typeof(AttributeProviderAttribute)] == null)
                    { 
                        AttributeCollection debugAttrs = debugEvt.Attributes; 
                        DebugValidate(evt.EventType, attrs, debugAttrs);
                    } 
                }
            }
            #endif
        } 

        ///  
        ///     Debug code that runs the output of a TypeDescriptor query into a debug 
        ///     type descriptor that uses the V1.0 algorithm.  This code will assert
        ///     if the two type descriptors do not agree. 
        /// 
        [Conditional("DEBUG")]
        private static void DebugValidate(EventDescriptorCollection events, object instance, Attribute[] attributes, bool noCustomTypeDesc)
        { 
            #if DEBUG
            if (!DebugShouldValidate(instance)) return; 
            EventDescriptorCollection debugEvents = DebugTypeDescriptor.GetEvents(instance, attributes, noCustomTypeDesc); 
            Debug.Assert(debugEvents.Count == events.Count, "TypeDescriptor engine Validation Failure. Event counts differ.");
            foreach(EventDescriptor debugEvt in debugEvents) 
            {
                EventDescriptor evt = null;

                foreach(EventDescriptor realEvt in events) 
                {
                    if (realEvt.Name.Equals(debugEvt.Name) && realEvt.EventType == debugEvt.EventType && realEvt.ComponentType == debugEvt.ComponentType) 
                    { 
                        evt = realEvt;
                        break; 
                    }
                }

                Debug.Assert(evt != null, "TypeDescriptor engine Validation Failure. Event " + debugEvt.Name + " does not exist or is of the wrong type."); 
                if (evt != null)
                { 
                    AttributeCollection attrs = evt.Attributes; 
                    if (attrs[typeof(AttributeProviderAttribute)] == null)
                    { 
                        AttributeCollection debugAttrs = debugEvt.Attributes;
                        DebugValidate(evt.EventType, attrs, debugAttrs);
                    }
                } 
            }
            #endif 
        } 

        ///  
        ///     Debug code that runs the output of a TypeDescriptor query into a debug
        ///     type descriptor that uses the V1.0 algorithm.  This code will assert
        ///     if the two type descriptors do not agree.
        ///  
        [Conditional("DEBUG")]
        private static void DebugValidate(PropertyDescriptorCollection properties, Type type, Attribute[] attributes) 
        { 
            #if DEBUG
            if (!DebugShouldValidate(type)) return; 
            PropertyDescriptorCollection debugProperties = DebugTypeDescriptor.GetProperties(type, attributes);

            if (debugProperties.Count > properties.Count)
            { 
                foreach(PropertyDescriptor debugProp in debugProperties)
                { 
                    PropertyDescriptor prop = null; 

                    foreach(PropertyDescriptor realProp in properties) 
                    {
                        if (realProp.Name.Equals(debugProp.Name) && realProp.PropertyType == debugProp.PropertyType && realProp.ComponentType == debugProp.ComponentType)
                        {
                            prop = realProp; 
                            break;
                        } 
                    } 

                    if (prop == null) 
                    {
                        Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} should exist.", debugProp.Name, debugProp.GetType().Name));
                    }
                } 
            }
            else if (properties.Count > debugProperties.Count) 
            { 
                foreach(PropertyDescriptor prop in properties)
                { 
                    PropertyDescriptor debugProp = null;

                    foreach(PropertyDescriptor realProp in debugProperties)
                    { 
                        if (realProp.Name.Equals(prop.Name) && realProp.PropertyType == prop.PropertyType && realProp.ComponentType == prop.ComponentType)
                        { 
                            debugProp = realProp; 
                            break;
                        } 
                    }

                    if (debugProp == null)
                    { 
                        Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} should not exist.", prop.Name, prop.GetType().Name));
                    } 
                } 
            }
            else 
            {
                foreach(PropertyDescriptor debugProp in debugProperties)
                {
                    PropertyDescriptor prop = null; 

                    foreach(PropertyDescriptor realProp in properties) 
                    { 
                        if (realProp.Name.Equals(debugProp.Name) && realProp.PropertyType == debugProp.PropertyType && realProp.ComponentType == debugProp.ComponentType)
                        { 
                            prop = realProp;
                            break;
                        }
                    } 

                    Debug.Assert(prop != null, string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} exists but perhaps type mismatched?", debugProp.Name, debugProp.GetType().Name)); 
                    if (prop != null) 
                    {
                        AttributeCollection attrs = prop.Attributes; 
                        if (attrs[typeof(AttributeProviderAttribute)] == null)
                        {
                            AttributeCollection debugAttrs = debugProp.Attributes;
                            DebugValidate(prop.PropertyType, attrs, debugAttrs); 
                        }
                    } 
                } 
            }
#endif 
        }

        /// 
        ///     Debug code that runs the output of a TypeDescriptor query into a debug 
        ///     type descriptor that uses the V1.0 algorithm.  This code will assert
        ///     if the two type descriptors do not agree. 
        ///  
        [Conditional("DEBUG")]
        private static void DebugValidate(PropertyDescriptorCollection properties, object instance, Attribute[] attributes, bool noCustomTypeDesc) 
        {
            #if DEBUG
            if (!DebugShouldValidate(instance)) return;
            PropertyDescriptorCollection debugProperties = DebugTypeDescriptor.GetProperties(instance, attributes, noCustomTypeDesc); 

            if (debugProperties.Count > properties.Count) 
            { 
                foreach(PropertyDescriptor debugProp in debugProperties)
                { 
                    PropertyDescriptor prop = null;

                    foreach(PropertyDescriptor realProp in properties)
                    { 
                        if (realProp.Name.Equals(debugProp.Name) && realProp.PropertyType == debugProp.PropertyType && realProp.ComponentType == debugProp.ComponentType)
                        { 
                            prop = realProp; 
                            break;
                        } 
                    }

                    if (prop == null)
                    { 
                        Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} should exist.", debugProp.Name, debugProp.GetType().Name));
                    } 
                } 
            }
            else if (properties.Count > debugProperties.Count) 
            {
                foreach(PropertyDescriptor prop in properties)
                {
                    PropertyDescriptor debugProp = null; 

                    foreach(PropertyDescriptor realProp in debugProperties) 
                    { 
                        if (realProp.Name.Equals(prop.Name) && realProp.PropertyType == prop.PropertyType && realProp.ComponentType == prop.ComponentType)
                        { 
                            debugProp = realProp;
                            break;
                        }
                    } 

                    if (debugProp == null) 
                    { 
                        Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} should not exist.", prop.Name, prop.GetType().Name));
                    } 
                }
            }
            else
            { 
                foreach(PropertyDescriptor debugProp in debugProperties)
                { 
                    PropertyDescriptor prop = null; 

                    foreach(PropertyDescriptor realProp in properties) 
                    {
                        if (realProp.Name.Equals(debugProp.Name) && realProp.PropertyType == debugProp.PropertyType && realProp.ComponentType == debugProp.ComponentType)
                        {
                            prop = realProp; 
                            break;
                        } 
                    } 

                    Debug.Assert(prop != null, string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} exists but perhaps type mismatched?", debugProp.Name, debugProp.GetType().Name)); 
                    if (prop != null)
                    {
                        AttributeCollection attrs = prop.Attributes;
                        if (attrs[typeof(AttributeProviderAttribute)] == null) 
                        {
                            AttributeCollection debugAttrs = debugProp.Attributes; 
                            DebugValidate(prop.PropertyType, attrs, debugAttrs); 
                        }
                    } 
                }
            }
#endif
        } 

        ///  
        ///     This  API is used to remove any members from the given 
        ///     collection that do not match the attribute array.  If members
        ///     need to be removed, a new ArrayList wil be created that 
        ///     contains only the remaining members. The API returns
        ///     NULL if it did not need to filter any members.
        /// 
        private static ArrayList FilterMembers(IList members, Attribute[] attributes) { 
            ArrayList newMembers = null;
            int memberCount = members.Count; 
 
            for (int idx = 0; idx < memberCount; idx++) {
 
                bool hide = false;

                for (int attrIdx = 0; attrIdx < attributes.Length; attrIdx++) {
                    if (ShouldHideMember((MemberDescriptor)members[idx], attributes[attrIdx])) { 
                        hide = true;
                        break; 
                    } 
                }
 
                if (hide) {
                    // We have to hide.  If this is the first time, we need to init
                    // newMembers to have all the valid members we have previously
                    // hit. 
                    if (newMembers == null) {
                        newMembers = new ArrayList(memberCount); 
                        for (int validIdx = 0; validIdx < idx; validIdx++) { 
                            newMembers.Add(members[validIdx]);
                        } 
                    }
                }
                else if (newMembers != null) {
                        newMembers.Add(members[idx]); 
                }
 
            } 

            return newMembers; 
        }

        /// 
        ///     The GetAssociation method returns the correct object to invoke 
        ///     for the requested type.  It never returns null.
        ///  
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        public static object GetAssociation(Type type, object primary)
        { 
            if (type == null)
            {
                throw new ArgumentNullException("type");
            } 

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

            object associatedObject = primary;

            if (!type.IsInstanceOfType(primary)) 
            {
                // Check our association table for a match. 
                // 
                Hashtable assocTable = _associationTable;
                if (assocTable != null) 
                {
                    IList associations = (IList)assocTable[primary];
                    if (associations != null)
                    { 
                        lock(associations)
                        { 
                            for (int idx = associations.Count - 1; idx >= 0; idx--) 
                            {
                                // Look for an associated object that has a type that 
                                // matches the given type.
                                //
                                WeakReference weakRef = (WeakReference)associations[idx];
                                object secondary = weakRef.Target; 
                                if (secondary == null)
                                { 
                                    Trace("Associations : Removing dead reference in assocation table"); 
                                    associations.RemoveAt(idx);
                                } 
                                else if (type.IsInstanceOfType(secondary))
                                {
                                    Trace("Associations : Associated {0} to {1}", primary.GetType().Name, secondary.GetType().Name);
                                    associatedObject = secondary; 
                                }
                            } 
                        } 
                    }
                } 

                // Not in our table.  We have a default association with a designer
                // if that designer is a component.
                // 
                if (associatedObject == primary)
                { 
                    IComponent component = primary as IComponent; 
                    if (component != null)
                    { 
                        ISite site = component.Site;

                        if (site != null && site.DesignMode)
                        { 
                            IDesignerHost host = site.GetService(typeof(IDesignerHost)) as IDesignerHost;
                            if (host != null) 
                            { 
                                object designer = host.GetDesigner(component);
 
                                // We only use the designer if it has a compatible class.  If we
                                // got here, we're probably hosed because the user just passed in
                                // an object that this PropertyDescriptor can't munch on, but it's
                                // clearer to use that object instance instead of it's designer. 
                                //
                                if (designer != null && type.IsInstanceOfType(designer)) 
                                { 
                                    Trace("Associations : Associated {0} to {1}", primary.GetType().Name, designer.GetType().Name);
                                    associatedObject = designer; 
                                }
                            }
                        }
                    } 
                }
            } 
 
            return associatedObject;
        } 

        /// 
        ///     Gets a collection of attributes for the specified type of component.
        ///  
        public static AttributeCollection GetAttributes(Type componentType)
        { 
            if (componentType == null) 
            {
                Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here"); 
                return new AttributeCollection((Attribute[])null);
            }

            AttributeCollection attributes = GetDescriptor(componentType, "componentType").GetAttributes(); 
            DebugValidate(attributes, componentType);
            return attributes; 
        } 

        ///  
        ///     Gets a collection of attributes for the specified component.
        /// 
        public static AttributeCollection GetAttributes(object component)
        { 
            return GetAttributes(component, false);
        } 
 
        /// 
        ///     Gets a collection of attributes for the specified component. 
        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static AttributeCollection GetAttributes(object component, bool noCustomTypeDesc)
        { 
            if (component == null)
            { 
                Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here"); 
                return new AttributeCollection((Attribute[])null);
            } 

            // We create a sort of pipeline for mucking with metadata.  The pipeline
            // goes through the following process:
            // 
            // 1.  Merge metadata from extenders.
            // 2.  Allow services to filter the metadata 
            // 3.  If an attribute filter was specified, apply that. 
            //
            // The goal here is speed.  We get speed by not copying or 
            // allocating memory.  We do this by allowing each phase of the
            // pipeline to cache its data in the object cache.  If
            // a phase makes a change to the results, this change must cause
            // successive phases to recompute their results as well.  "Results" is 
            // always a collection, and the various stages of the pipeline may
            // replace or modify this collection (depending on if it's a 
            // read-only IList or not).  It is possible for the orignal 
            // descriptor or attribute collection to pass through the entire
            // pipeline without modification. 
            //
            ICustomTypeDescriptor typeDesc = GetDescriptor(component, noCustomTypeDesc);
            ICollection results = typeDesc.GetAttributes();
 
            // If we are handed a custom type descriptor we have several choices of action
            // we can take.  If noCustomTypeDesc is true, it means that the custom type 
            // descriptor is trying to find a baseline set of properties.  In this case 
            // we should merge in extended properties, but we do not let designers filter
            // because we're not done with the property set yet.  If noCustomTypeDesc 
            // is false, we don't do extender properties because the custom type descriptor
            // has already added them.  In this case, we are doing a final pass so we
            // want to apply filtering.  Finally, if the incoming object is not a custom
            // type descriptor, we do extenders and the filter. 
            //
            if (component is ICustomTypeDescriptor) 
            { 
                if (noCustomTypeDesc)
                { 
                    ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component);
                    if (extDesc != null)
                    {
                        ICollection extResults = extDesc.GetAttributes(); 
                        results = PipelineMerge(PIPELINE_ATTRIBUTES, results, extResults, component, null);
                    } 
                } 
                else
                { 
                    results = PipelineFilter(PIPELINE_ATTRIBUTES, results, component, null);
                }
            }
            else 
            {
                IDictionary cache = GetCache(component); 
 
                results = PipelineInitialize(PIPELINE_ATTRIBUTES, results, cache);
 
                ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component);
                if (extDesc != null)
                {
                    ICollection extResults = extDesc.GetAttributes(); 
                    results = PipelineMerge(PIPELINE_ATTRIBUTES, results, extResults, component, cache);
                } 
 
                results = PipelineFilter(PIPELINE_ATTRIBUTES, results, component, cache);
            } 

            AttributeCollection attrs = results as AttributeCollection;
            if (attrs == null)
            { 
                Trace("Attributes : Allocated new attribute collection for {0}", component.GetType().Name);
                Attribute[] attrArray = new Attribute[results.Count]; 
                results.CopyTo(attrArray, 0); 
                attrs = new AttributeCollection(attrArray);
            } 

            DebugValidate(attrs, component, noCustomTypeDesc);
            return attrs;
        } 

        ///  
        ///     Helper function to obtain a cache for the given object. 
        /// 
        internal static IDictionary GetCache(object instance) 
        {
            return NodeFor(instance).GetCache(instance);
        }
 
        /// 
        ///     Gets the name of the class for the specified component. 
        ///  
        public static string GetClassName(object component)
        { 
            return GetClassName(component, false);
        }

        ///  
        ///     Gets the name of the class for the specified component.
        ///  
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        public static string GetClassName(object component, bool noCustomTypeDesc)
        { 
            return GetDescriptor(component, noCustomTypeDesc).GetClassName();
        }

        ///  
        ///     Gets the name of the class for the specified type.
        ///  
        public static string GetClassName(Type componentType) 
        {
            return GetDescriptor(componentType, "componentType").GetClassName(); 
        }

        /// 
        ///       The name of the class for the specified component. 
        /// 
        public static string GetComponentName(object component) 
        { 
            return GetComponentName(component, false);
        } 

        /// 
        ///    Gets the name of the class for the specified component.
        ///  
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static string GetComponentName(object component, bool noCustomTypeDesc) 
        { 
            return GetDescriptor(component, noCustomTypeDesc).GetComponentName();
        } 

        /// 
        ///    Gets a type converter for the type of the specified component.
        ///  
        public static TypeConverter GetConverter(object component)
        { 
            return GetConverter(component, false); 
        }
 
        /// 
        ///    Gets a type converter for the type of the specified component.
        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        public static TypeConverter GetConverter(object component, bool noCustomTypeDesc)
        { 
            TypeConverter converter = GetDescriptor(component, noCustomTypeDesc).GetConverter(); 
            DebugValidate(converter, component, noCustomTypeDesc);
            return converter; 
        }

        /// 
        ///    Gets a type converter for the specified type. 
        /// 
        [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] 
        public static TypeConverter GetConverter(Type type) 
        {
            TypeConverter converter = GetDescriptor(type, "type").GetConverter(); 
            DebugValidate(converter, type);
            return converter;
        }
 
        /// 
        ///     Gets the default event for the specified type of component. 
        ///  
        public static EventDescriptor GetDefaultEvent(Type componentType)
        { 
            if (componentType == null)
            {
                Debug.Fail("COMPAT:  Returning null, but you should not pass null here");
                return null; 
            }
 
            return GetDescriptor(componentType, "componentType").GetDefaultEvent(); 
        }
 
        /// 
        ///     Gets the default event for the specified component.
        /// 
        public static EventDescriptor GetDefaultEvent(object component) 
        {
            return GetDefaultEvent(component, false); 
        } 

        ///  
        ///     Gets the default event for a component.
        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static EventDescriptor GetDefaultEvent(object component, bool noCustomTypeDesc) 
        {
            if (component == null) 
            { 
                Debug.Fail("COMPAT:  Returning null, but you should not pass null here");
                return null; 
            }

            return GetDescriptor(component, noCustomTypeDesc).GetDefaultEvent();
        } 

        ///  
        ///     Gets the default property for the specified type of component. 
        /// 
        public static PropertyDescriptor GetDefaultProperty(Type componentType) 
        {
            if (componentType == null)
            {
                Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here"); 
                return null;
            } 
 
            return GetDescriptor(componentType, "componentType").GetDefaultProperty();
        } 

        /// 
        ///     Gets the default property for the specified component.
        ///  
        public static PropertyDescriptor GetDefaultProperty(object component)
        { 
            return GetDefaultProperty(component, false); 
        }
 
        /// 
        ///     Gets the default property for the specified component.
        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        public static PropertyDescriptor GetDefaultProperty(object component, bool noCustomTypeDesc)
        { 
            if (component == null) 
            {
                Debug.Fail("COMPAT:  Returning null, but you should not pass null here"); 
                return null;
            }

            return GetDescriptor(component, noCustomTypeDesc).GetDefaultProperty(); 
        }
 
        ///  
        ///     Returns a custom type descriptor for the given type.
        ///     Performs arg checking so callers don't have to. 
        /// 
        internal static ICustomTypeDescriptor GetDescriptor(Type type, string typeName)
        {
            if (type == null) 
            {
                throw new ArgumentNullException(typeName); 
            } 

            return NodeFor(type).GetTypeDescriptor(type); 
        }

        /// 
        ///     Returns a custom type descriptor for the given instance. 
        ///     Performs arg checking so callers don't have to.  This
        ///     will call through to instance if it is a custom type 
        ///     descriptor. 
        /// 
        internal static ICustomTypeDescriptor GetDescriptor(object component, bool noCustomTypeDesc) 
        {
            if (component == null)
            {
                throw new ArgumentException("component"); 
            }
 
            if (component is IUnimplemented) { 
                throw new NotSupportedException(SR.GetString(SR.TypeDescriptorUnsupportedRemoteObject, component.GetType().FullName));
            } 


            ICustomTypeDescriptor desc = NodeFor(component).GetTypeDescriptor(component);
            ICustomTypeDescriptor d = component as ICustomTypeDescriptor; 
            if (!noCustomTypeDesc && d != null)
            { 
                desc = new MergedTypeDescriptor(d, desc); 
            }
 
            return desc;
        }

        ///  
        ///     Returns an extended custom type descriptor for the given instance.
        ///  
        internal static ICustomTypeDescriptor GetExtendedDescriptor(object component) 
        {
            if (component == null) 
            {
                throw new ArgumentException("component");
            }
 
            return NodeFor(component).GetExtendedTypeDescriptor(component);
        } 
 
        /// 
        ///     Gets an editor with the specified base type for the 
        ///     specified component.
        /// 
        public static object GetEditor(object component, Type editorBaseType)
        { 
            return GetEditor(component, editorBaseType, false);
        } 
 
        /// 
        ///     Gets an editor with the specified base type for the 
        ///     specified component.
        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static object GetEditor(object component, Type editorBaseType, bool noCustomTypeDesc) 
        {
            if (editorBaseType == null) 
            { 
                throw new ArgumentNullException("editorBaseType");
            } 

            return GetDescriptor(component, noCustomTypeDesc).GetEditor(editorBaseType);
        }
 
        /// 
        ///    Gets an editor with the specified base type for the specified type. 
        ///  
        public static object GetEditor(Type type, Type editorBaseType)
        { 
            if (editorBaseType == null)
            {
                throw new ArgumentNullException("editorBaseType");
            } 

            return GetDescriptor(type, "type").GetEditor(editorBaseType); 
        } 

        ///  
        ///     Gets a collection of events for a specified type of component.
        /// 
        public static EventDescriptorCollection GetEvents(Type componentType)
        { 
            if (componentType == null)
            { 
                Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here"); 
                return new EventDescriptorCollection(null, true);
            } 

            return GetDescriptor(componentType, "componentType").GetEvents();
        }
 
        /// 
        ///     Gets a collection of events for a specified type of 
        ///     component using a specified array of attributes as a filter. 
        /// 
        public static EventDescriptorCollection GetEvents(Type componentType, Attribute[] attributes) 
        {
            if (componentType == null)
            {
                Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here"); 
                return new EventDescriptorCollection(null, true);
            } 
 
            EventDescriptorCollection events = GetDescriptor(componentType, "componentType").GetEvents(attributes);
 
            if (attributes != null && attributes.Length > 0) {
                ArrayList filteredEvents = FilterMembers(events, attributes);
                if (filteredEvents != null) {
                    events = new EventDescriptorCollection((EventDescriptor[])filteredEvents.ToArray(typeof(EventDescriptor)), true); 
                }
            } 
 
            DebugValidate(events, componentType, attributes);
            return events; 
        }

        /// 
        ///     Gets a collection of events for a specified component. 
        /// 
        public static EventDescriptorCollection GetEvents(object component) 
        { 
            return GetEvents(component, null, false);
        } 

        /// 
        ///     Gets a collection of events for a specified component.
        ///  
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static EventDescriptorCollection GetEvents(object component, bool noCustomTypeDesc) 
        { 
            return GetEvents(component, null, noCustomTypeDesc);
        } 

        /// 
        ///     Gets a collection of events for a specified component
        ///     using a specified array of attributes as a filter. 
        /// 
        public static EventDescriptorCollection GetEvents(object component, Attribute[] attributes) 
        { 
            return GetEvents(component, attributes, false);
        } 

        /// 
        ///     Gets a collection of events for a specified component
        ///     using a specified array of attributes as a filter. 
        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        public static EventDescriptorCollection GetEvents(object component, Attribute[] attributes, bool noCustomTypeDesc) 
        {
            if (component == null) 
            {
                Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here");
                return new EventDescriptorCollection(null, true);
            } 

            // We create a sort of pipeline for mucking with metadata.  The pipeline 
            // goes through the following process: 
            //
            // 1.  Merge metadata from extenders. 
            // 2.  Allow services to filter the metadata
            // 3.  If an attribute filter was specified, apply that.
            //
            // The goal here is speed.  We get speed by not copying or 
            // allocating memory.  We do this by allowing each phase of the
            // pipeline to cache its data in the object cache.  If 
            // a phase makes a change to the results, this change must cause 
            // successive phases to recompute their results as well.  "Results" is
            // always a collection, and the various stages of the pipeline may 
            // replace or modify this collection (depending on if it's a
            // read-only IList or not).  It is possible for the orignal
            // descriptor or attribute collection to pass through the entire
            // pipeline without modification. 
            //
            ICustomTypeDescriptor typeDesc = GetDescriptor(component, noCustomTypeDesc); 
            ICollection results; 

            // If we are handed a custom type descriptor we have several choices of action 
            // we can take.  If noCustomTypeDesc is true, it means that the custom type
            // descriptor is trying to find a baseline set of events.  In this case
            // we should merge in extended events, but we do not let designers filter
            // because we're not done with the event set yet.  If noCustomTypeDesc 
            // is false, we don't do extender events because the custom type descriptor
            // has already added them.  In this case, we are doing a final pass so we 
            // want to apply filtering.  Finally, if the incoming object is not a custom 
            // type descriptor, we do extenders and the filter.
            // 
            if (component is ICustomTypeDescriptor)
            {
                results = typeDesc.GetEvents(attributes);
                if (noCustomTypeDesc) 
                {
                    ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component); 
                    if (extDesc != null) 
                    {
                        ICollection extResults = extDesc.GetEvents(attributes); 
                        results = PipelineMerge(PIPELINE_EVENTS, results, extResults, component, null);
                    }
                }
                else 
                {
                    results = PipelineFilter(PIPELINE_EVENTS, results, component, null); 
                    results = PipelineAttributeFilter(PIPELINE_EVENTS, results, attributes, component, null); 
                }
            } 
            else
            {
                IDictionary cache = GetCache(component);
                results = typeDesc.GetEvents(attributes); 
                results = PipelineInitialize(PIPELINE_EVENTS, results, cache);
                ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component); 
                if (extDesc != null) 
                {
                    ICollection extResults = extDesc.GetEvents(attributes); 
                    results = PipelineMerge(PIPELINE_EVENTS, results, extResults, component, cache);
                }

                results = PipelineFilter(PIPELINE_EVENTS, results, component, cache); 
                results = PipelineAttributeFilter(PIPELINE_EVENTS, results, attributes, component, cache);
            } 
 
            EventDescriptorCollection evts = results as EventDescriptorCollection;
            if (evts == null) 
            {
                Trace("Events : Allocated new event collection for {0}", component.GetType().Name);
                EventDescriptor[] eventArray = new EventDescriptor[results.Count];
                results.CopyTo(eventArray, 0); 
                evts = new EventDescriptorCollection(eventArray, true);
            } 
 
            DebugValidate(evts, component, attributes, noCustomTypeDesc);
 
            return evts;
        }

        ///  
        ///     This method is invoked during filtering when a name
        ///     collision is encountered between two properties or events.  This returns 
        ///     a suffix that can be appended to the name to make 
        ///     it unique.  This will first attempt ot use the name of the
        ///     extender.  Failing that it will fall back to a static 
        ///     index that is continually incremented.
        /// 
        private static string GetExtenderCollisionSuffix(MemberDescriptor member)
        { 
            string suffix = null;
 
            ExtenderProvidedPropertyAttribute exAttr = member.Attributes[typeof(ExtenderProvidedPropertyAttribute)] as ExtenderProvidedPropertyAttribute; 
            if (exAttr != null)
            { 
                IExtenderProvider prov = exAttr.Provider;

                if (prov != null)
                { 
                    string name = null;
                    IComponent component = prov as IComponent; 
 
                    if (component != null && component.Site != null)
                    { 
                        name = component.Site.Name;
                    }

                    if (name == null || name.Length == 0) 
                    {
                        name = (_collisionIndex++).ToString(CultureInfo.InvariantCulture); 
                    } 

                    suffix = string.Format(CultureInfo.InvariantCulture, "_{0}", name); 
                }
            }

            return suffix; 
        }
 
        ///  
        ///     The name of the specified component, or null if the component has no name.
        ///     In many cases this will return the same value as GetComponentName. If the 
        ///     component resides in a nested container or has other nested semantics, it may
        ///     return a different fully qualfied name.
        /// 
        public static string GetFullComponentName(object component) { 
            if (component == null) throw new ArgumentNullException("component");
            return GetProvider(component).GetFullComponentName(component); 
        } 

        ///  
        ///     Gets a collection of properties for a specified type of component.
        /// 
        public static PropertyDescriptorCollection GetProperties(Type componentType)
        { 
            if (componentType == null)
            { 
                Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here"); 
                return new PropertyDescriptorCollection(null, true);
            } 

            return GetDescriptor(componentType, "componentType").GetProperties();
        }
 
        /// 
        ///    Gets a collection of properties for a specified type of 
        ///    component using a specified array of attributes as a filter. 
        /// 
        public static PropertyDescriptorCollection GetProperties(Type componentType, Attribute[] attributes) 
        {
            if (componentType == null)
            {
                Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here"); 
                return new PropertyDescriptorCollection(null, true);
            } 
 
            PropertyDescriptorCollection properties = GetDescriptor(componentType, "componentType").GetProperties(attributes);
 
            if (attributes != null && attributes.Length > 0) {
                ArrayList filteredProperties = FilterMembers(properties, attributes);
                if (filteredProperties != null) {
                    properties = new PropertyDescriptorCollection((PropertyDescriptor[])filteredProperties.ToArray(typeof(PropertyDescriptor)), true); 
                }
            } 
 
            DebugValidate(properties, componentType, attributes);
            return properties; 
        }

        /// 
        ///     Gets a collection of properties for a specified component. 
        /// 
        public static PropertyDescriptorCollection GetProperties(object component) 
        { 
            return GetProperties(component, false);
        } 

        /// 
        ///     Gets a collection of properties for a specified component.
        ///  
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static PropertyDescriptorCollection GetProperties(object component, bool noCustomTypeDesc) 
        { 
            return GetPropertiesImpl(component, null, noCustomTypeDesc, true);
        } 

        /// 
        ///    Gets a collection of properties for a specified
        ///    component using a specified array of attributes 
        ///    as a filter.
        ///  
        public static PropertyDescriptorCollection GetProperties(object component, Attribute[] attributes) 
        {
            return GetProperties(component, attributes, false); 
        }

        /// 
        ///    Gets a collection of properties for a specified 
        ///       component using a specified array of attributes
        ///       as a filter. 
        ///  
        public static PropertyDescriptorCollection GetProperties(object component, Attribute[] attributes, bool noCustomTypeDesc) {
            return GetPropertiesImpl(component, attributes, noCustomTypeDesc, false); 
        }

        /// 
        ///    Gets a collection of properties for a specified component. Uses the attribute filter 
        ///    only if noAttributes is false. This is to preserve backward compat for the case when
        ///    no attribute filter was passed in (as against passing in null). 
        ///  
        private static PropertyDescriptorCollection GetPropertiesImpl(object component, Attribute[] attributes, bool noCustomTypeDesc, bool noAttributes) {
            if (component == null) 
            {
                Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here");
                return new PropertyDescriptorCollection(null, true);
            } 

            // We create a sort of pipeline for mucking with metadata.  The pipeline 
            // goes through the following process: 
            //
            // 1.  Merge metadata from extenders. 
            // 2.  Allow services to filter the metadata
            // 3.  If an attribute filter was specified, apply that.
            //
            // The goal here is speed.  We get speed by not copying or 
            // allocating memory.  We do this by allowing each phase of the
            // pipeline to cache its data in the object cache.  If 
            // a phase makes a change to the results, this change must cause 
            // successive phases to recompute their results as well.  "Results" is
            // always a collection, and the various stages of the pipeline may 
            // replace or modify this collection (depending on if it's a
            // read-only IList or not).  It is possible for the orignal
            // descriptor or attribute collection to pass through the entire
            // pipeline without modification. 
            //
            ICustomTypeDescriptor typeDesc = GetDescriptor(component, noCustomTypeDesc); 
            ICollection results; 

            // If we are handed a custom type descriptor we have several choices of action 
            // we can take.  If noCustomTypeDesc is true, it means that the custom type
            // descriptor is trying to find a baseline set of properties.  In this case
            // we should merge in extended properties, but we do not let designers filter
            // because we're not done with the property set yet.  If noCustomTypeDesc 
            // is false, we don't do extender properties because the custom type descriptor
            // has already added them.  In this case, we are doing a final pass so we 
            // want to apply filtering.  Finally, if the incoming object is not a custom 
            // type descriptor, we do extenders and the filter.
            // 
            if (component is ICustomTypeDescriptor)
            {
                results = noAttributes ? typeDesc.GetProperties() : typeDesc.GetProperties(attributes);
                if (noCustomTypeDesc) 
                {
                    ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component); 
                    if (extDesc != null) 
                    {
                        ICollection extResults = noAttributes ? extDesc.GetProperties() : extDesc.GetProperties(attributes); 
                        results = PipelineMerge(PIPELINE_PROPERTIES, results, extResults, component, null);
                    }
                }
                else 
                {
                    results = PipelineFilter(PIPELINE_PROPERTIES, results, component, null); 
                    results = PipelineAttributeFilter(PIPELINE_PROPERTIES, results, attributes, component, null); 
                }
            } 
            else
            {
                IDictionary cache = GetCache(component);
                results = noAttributes ? typeDesc.GetProperties() : typeDesc.GetProperties(attributes); 
                results = PipelineInitialize(PIPELINE_PROPERTIES, results, cache);
                ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component); 
                if (extDesc != null) 
                {
                    ICollection extResults = noAttributes ? extDesc.GetProperties() : extDesc.GetProperties(attributes); 
                    results = PipelineMerge(PIPELINE_PROPERTIES, results, extResults, component, cache);
                }

                results = PipelineFilter(PIPELINE_PROPERTIES, results, component, cache); 
                results = PipelineAttributeFilter(PIPELINE_PROPERTIES, results, attributes, component, cache);
            } 
 
            PropertyDescriptorCollection props = results as PropertyDescriptorCollection;
            if (props == null) 
            {
                Trace("Properties : Allocated new property collection for {0}", component.GetType().Name);
                PropertyDescriptor[] propArray = new PropertyDescriptor[results.Count];
                results.CopyTo(propArray, 0); 
                props = new PropertyDescriptorCollection(propArray, true);
            } 
 
            DebugValidate(props, component, attributes, noCustomTypeDesc);
 
            return props;
        }

        ///  
        ///     The GetProvider method returns a type description provider for
        ///     the given object or type.  This will always return a type description 
        ///     provider.  Even the default TypeDescriptor implementation is built on 
        ///     a TypeDescriptionProvider, and this will be returned unless there is
        ///     another provider that someone else has added. 
        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static TypeDescriptionProvider GetProvider(Type type)
        { 
            if (type == null)
            { 
                throw new ArgumentNullException("type"); 
            }
 
            return NodeFor(type, true);
        }

        ///  
        ///     The GetProvider method returns a type description provider for
        ///     the given object or type.  This will always return a type description 
        ///     provider.  Even the default TypeDescriptor implementation is built on 
        ///     a TypeDescriptionProvider, and this will be returned unless there is
        ///     another provider that someone else has added. 
        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static TypeDescriptionProvider GetProvider(object instance)
        { 
            if (instance == null)
            { 
                throw new ArgumentNullException("instance"); 
            }
 
            return NodeFor(instance, true);
        }

        ///  
        ///     This method returns a type description provider, but instead of creating
        ///     a delegating provider for the type, this will walk all base types until 
        ///     it locates a provider.  The provider returned cannot be cached.  This 
        ///     method is used by the DelegatingTypeDescriptionProvider to efficiently
        ///     locate the provider to delegate to. 
        /// 
        internal static TypeDescriptionProvider GetProviderRecursive(Type type) {
            return NodeFor(type, false);
        } 

        ///  
        ///     Returns an Type instance that can be used to perform reflection. 
        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        public static Type GetReflectionType(Type type)
        {
            if (type == null)
            { 
                throw new ArgumentNullException("type");
            } 
 
            return NodeFor(type).GetReflectionType(type);
        } 

        /// 
        ///     Returns an Type instance that can be used to perform reflection.
        ///  
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static Type GetReflectionType(object instance) 
        { 
            if (instance == null)
            { 
                throw new ArgumentNullException("instance");
            }

            return NodeFor(instance).GetReflectionType(instance); 
        }
 
        ///  
        ///     Retrieves the head type description node for a type.
        ///     A head node pointing to a reflection based type description 
        ///     provider will be created on demand.  This does not create
        ///     a delegator, in which case the node returned may be
        ///     a base type node.
        ///  
        private static TypeDescriptionNode NodeFor(Type type) {
            return NodeFor(type, false); 
        } 

        ///  
        ///     Retrieves the head type description node for a type.
        ///     A head node pointing to a reflection based type description
        ///     provider will be created on demand.
        /// 
        ///     If createDelegator is true, this method will create a delegation
        ///     node for a type if the type has no node of its own.  Delegation 
        ///     nodes should be created if you are going to hand this node 
        ///     out to a user.  Without a delegation node, user code could
        ///     skip providers that are added after their call.  Delegation 
        ///     nodes solve that problem.
        ///
        ///     If createDelegator is false, this method will recurse up the
        ///     base type chain looking for nodes. 
        /// 
        private static TypeDescriptionNode NodeFor(Type type, bool createDelegator) { 
            Debug.Assert(type != null, "Caller should validate"); 
            CheckDefaultProvider(type);
 
            // First, check our provider type table to see if we have a matching
            // provider for this type.  The provider type table is a cache that
            // matches types to providers.  When a new provider is added or
            // an existing one removed, the provider type table is torn 
            // down and automatically rebuilt on demand.
            // 
            TypeDescriptionNode node = null; 
            Type searchType = type;
 
            while (node == null) {

                node = (TypeDescriptionNode)_providerTypeTable[searchType];
                if (node == null) { 
                    node = (TypeDescriptionNode)_providerTable[searchType];
                } 
 
                if (node == null) {
                    Type baseType = searchType.BaseType; 

                    if (searchType == typeof(object) || baseType == null) {
                        lock(_providerTable) {
                            node = (TypeDescriptionNode)_providerTable[searchType]; 

                            if (node == null) { 
                                // The reflect type description provider is a default provider that 
                                // can provide type information for all objects.
                                node = new TypeDescriptionNode(new ReflectTypeDescriptionProvider()); 
                                _providerTable[searchType] = node;
                                Trace("Nodes : Allocated new type node.  Now {0} nodes", _providerTable.Count);
                            }
                        } 
                    }
                    else if (createDelegator) { 
                        node = new TypeDescriptionNode(new DelegatingTypeDescriptionProvider(baseType)); 
                        _providerTypeTable[searchType] = node;
                    } 
                    else {
                        // Continue our search
                        searchType = baseType;
                    } 
                }
            } 
 
            return node;
        } 

        /// 
        ///     Retrieves the head type description node for an instance.
        ///     Instance-based node lists are rare.  If a node list is not 
        ///     available for a given instance, this will return the head node
        ///     for the instance's type. 
        ///  
        private static TypeDescriptionNode NodeFor(object instance)
        { 
            return NodeFor(instance, false);
        }

        ///  
        ///     Retrieves the head type description node for an instance.
        ///     Instance-based node lists are rare.  If a node list is not 
        ///     available for a given instance, this will return the head node 
        ///     for the instance's type.  This variation offers a bool called
        ///     createDelegator.  If true and there is no node list for this 
        ///     instance, NodeFor will create a temporary "delegator node" that,
        ///     when queried, will delegate to the type stored in the instance.
        ///     This is done on demand, which means if someone else added a
        ///     type description provider for the instance's type the delegator 
        ///     would pick up the new type.  If a query is being made that does
        ///     not involve publicly exposing the type description provider for 
        ///     the instance, the query should pass in fase (the default) for 
        ///     createDelegator because no object will be created.
        ///  
        private static TypeDescriptionNode NodeFor(object instance, bool createDelegator)
        {
            // For object instances, the provider cache key is not the object (that
            // would keep it in memory).  Instead, it is a subclass of WeakReference 
            // that overrides GetHashCode and Equals to make it appear to be the
            // object it is wrapping.  A GC'd object causes WeakReference to return 
            // false for all .Equals, but it always returns a valid hash code. 

            Debug.Assert(instance != null, "Caller should validate"); 

            TypeDescriptionNode node = (TypeDescriptionNode)_providerTable[instance];
            if (node == null)
            { 
                Type type = instance.GetType();
 
                if (type.IsCOMObject) 
                {
                    type = ComObjectType; 
                }

                if (createDelegator)
                { 
                    node = new TypeDescriptionNode(new DelegatingTypeDescriptionProvider(type));
                    Trace("Nodes : Allocated new instance node for {0}.  Now {1} nodes", type.Name, _providerTable.Count); 
                } 
                else
                { 
                    node = NodeFor(type);
                }
            }
 
            return node;
        } 
 
        /// 
        ///     Simple linked list code to remove an element 
        ///     from the list.  Returns the new head to the
        ///     list.  If the head points to an instance of
        ///     DelegatingTypeDescriptionProvider, we clear the
        ///     node because all it is doing is delegating elsewhere. 
        ///
        ///     Note that this behaves a little differently from normal 
        ///     linked list code.  In a normal linked list, you remove 
        ///     then target node and fixup the links.  In this linked
        ///     list, we remove the node AFTER the target node, fixup 
        ///     the links, and fixup the underlying providers that each
        ///     node references.  The reason for this is that most
        ///     providers keep a reference to the previous provider,
        ///     which is exposed as one of these nodes.  Therefore, 
        ///     to remove a provider the node following is most likely
        ///     referenced by that provider 
        ///  
        private static void NodeRemove(object key, TypeDescriptionProvider provider)
        { 
            lock(_providerTable)
            {
                TypeDescriptionNode head = (TypeDescriptionNode)_providerTable[key];
                TypeDescriptionNode target = head; 
                TypeDescriptionNode prev = null;
 
                while(target != null && target.Provider != provider) 
                {
                    prev = target; 
                    target = target.Next;
                }

                if (target != null) 
                {
                    // We have our target node.  There are three cases 
                    // to consider:  the target is in the middle, the head, 
                    // or the end.
 
                    if (target.Next != null) {
                        // If there is a node after the target node,
                        // steal the node's provider and store it
                        // at the target location.  This removes 
                        // the provider at the target location without
                        // the need to modify providers which may be 
                        // pointing to "target". 
                        target.Provider = target.Next.Provider;
 
                        // Now remove target.Next from the list
                        target.Next = target.Next.Next;

                        // If the new provider we got is a delegating 
                        // provider, we can remove this node from
                        // the list.  The delegating provider should 
                        // always be at the end of the node list. 
                        if (target == head && target.Provider is DelegatingTypeDescriptionProvider) {
                            Debug.Assert(target.Next == null, "Delegating provider should always be the last provider in the chain."); 
                            _providerTable.Remove(key);
                        }
                    }
                    else if (target != head) { 
                        // If target is the last node, we can't
                        // assign a new provider over to it.  What 
                        // we can do, however, is assign a delegating 
                        // provider into the target node.  This routes
                        // requests from the previous provider into 
                        // the next base type provider list.

                        // We don't do this if the target is the head.
                        // In that case, we can remove the node 
                        // altogether since no one is pointing to it.
 
                        Type keyType = key as Type; 
                        if (keyType == null) keyType = key.GetType();
 
                        target.Provider = new DelegatingTypeDescriptionProvider(keyType.BaseType);
                    }
                    else {
                        _providerTable.Remove(key); 
                    }
 
                    // Finally, clear our cache of provider types; it might be invalid 
                    // now.
                    _providerTypeTable.Clear(); 
                }
            }
        }
 
        /// 
        ///     This is the last stage in our filtering pipeline.  Here, we apply any 
        ///     user-defined filter. 
        /// 
        private static ICollection PipelineAttributeFilter(int pipelineType, ICollection members, Attribute[] filter, object instance, IDictionary cache) 
        {
            Debug.Assert(pipelineType != PIPELINE_ATTRIBUTES, "PipelineAttributeFilter is not supported for attributes");

            IList list = members as ArrayList; 

            if (filter == null || filter.Length == 0) 
            { 
                return members;
            } 

            // Now, check our cache.  The cache state is only valid
            // if the data coming into us is read-only.  If it is read-write,
            // that means something higher in the pipeline has already changed 
            // it so we must recompute anyway.
            // 
            if (cache != null && (list == null || list.IsReadOnly)) 
            {
                AttributeFilterCacheItem filterCache = cache[_pipelineAttributeFilterKeys[pipelineType]] as AttributeFilterCacheItem; 
                if (filterCache != null && filterCache.IsValid(filter))
                {
                    return filterCache.FilteredMembers;
                } 
            }
 
            // Our cache did not contain the correct state, so generate it. 
            //
            if (list == null || list.IsReadOnly) 
            {
                Trace("Pipeline : Filter needs to create member list for {0}", instance.GetType().Name);
                list = new ArrayList(members);
            } 

            ArrayList filterResult = FilterMembers(list, filter); 
            if (filterResult != null) list = filterResult; 

            // And, if we have a cache, store the updated state into it for future reference. 
            //
            if (cache != null)
            {
                ICollection cacheValue; 

                switch(pipelineType) 
                { 
                    case PIPELINE_PROPERTIES:
                        PropertyDescriptor[] propArray = new PropertyDescriptor[list.Count]; 
                        list.CopyTo(propArray, 0);
                        cacheValue = new PropertyDescriptorCollection(propArray, true);
                        break;
 
                    case PIPELINE_EVENTS:
                        EventDescriptor[] eventArray = new EventDescriptor[list.Count]; 
                        list.CopyTo(eventArray, 0); 
                        cacheValue = new EventDescriptorCollection(eventArray, true);
                        break; 

                    default:
                        Debug.Fail("unknown pipeline type");
                        cacheValue = null; 
                        break;
                } 
 
                Trace("Pipeline : Attribute Filter results being cached for {0}", instance.GetType().Name);
                AttributeFilterCacheItem filterCache = new AttributeFilterCacheItem(filter, cacheValue); 
                cache[_pipelineAttributeFilterKeys[pipelineType]] = filterCache;
            }

            return list; 
        }
 
        ///  
        ///     Metdata filtering is the third stage of our pipeline.
        ///     In this stage we check to see if the given object is a 
        ///     sited component that provides the ITypeDescriptorFilterService
        ///     object.  If it does, we allow the TDS to filter the metadata.
        ///     This will use the cache, if available, to store filtered
        ///     metdata. 
        /// 
        private static ICollection PipelineFilter(int pipelineType, ICollection members, object instance, IDictionary cache) 
        { 
            IComponent component = instance as IComponent;
            ITypeDescriptorFilterService componentFilter = null; 

            if (component != null)
            {
                ISite site = component.Site; 
                if (site != null)
                { 
                    componentFilter = site.GetService(typeof(ITypeDescriptorFilterService)) as ITypeDescriptorFilterService; 
                }
            } 

            // If we have no filter, there is nothing for us to do.
            //
            IList list = members as ArrayList; 

            if (componentFilter == null) 
            { 
                Debug.Assert(cache == null || list == null || !cache.Contains(_pipelineFilterKeys[pipelineType]), "Earlier pipeline stage should have removed our cache");
                return members; 
            }

            // Now, check our cache.  The cache state is only valid
            // if the data coming into us is read-only.  If it is read-write, 
            // that means something higher in the pipeline has already changed
            // it so we must recompute anyway. 
            // 
            if (cache != null && (list == null || list.IsReadOnly))
            { 
                FilterCacheItem cacheItem = cache[_pipelineFilterKeys[pipelineType]] as FilterCacheItem;
                if (cacheItem != null && cacheItem.IsValid(componentFilter)) {
                    return cacheItem.FilteredMembers;
                } 
            }
 
            // Cache either is dirty or doesn't exist.  Re-filter the members. 
            // We need to build an IDictionary of key->value pairs and invoke
            // Filter* on the filter service. 
            //
            Hashtable filterTable = new Hashtable(members.Count);
            bool cacheResults;
 
            switch(pipelineType)
            { 
                case PIPELINE_ATTRIBUTES: 
                    foreach(Attribute attr in members)
                    { 
                        filterTable[attr.TypeId] = attr;
                    }
                    cacheResults = componentFilter.FilterAttributes(component, filterTable);
                    break; 

                case PIPELINE_PROPERTIES: 
                case PIPELINE_EVENTS: 
                    foreach(MemberDescriptor desc in members)
                    { 
                        string descName = desc.Name;
                        // We must handle the case of duplicate property names
                        // because extender providers can provide any arbitrary
                        // name.  Our rule for this is simple:  If we find a 
                        // duplicate name, resolve it back to the extender
                        // provider that offered it and append "_" + the 
                        // provider name.  If the provider has no name, 
                        // then append the object hash code.
                        // 
                        if (filterTable.Contains(descName))
                        {
                            // First, handle the new property.  Because
                            // of the order in which we added extended 
                            // properties earlier in the pipeline, we can be
                            // sure that the new property is an extender.  We 
                            // cannot be sure that the existing property 
                            // in the table is an extender, so we will
                            // have to check. 
                            //
                            string suffix = GetExtenderCollisionSuffix(desc);
                            Debug.Assert(suffix != null, "Name collision with non-extender property.");
                            if (suffix != null) 
                            {
                                filterTable[descName + suffix] = desc; 
                            } 

                            // Now, handle the original property. 
                            //
                            MemberDescriptor origDesc = (MemberDescriptor)filterTable[descName];
                            suffix = GetExtenderCollisionSuffix(origDesc);
                            if (suffix != null) 
                            {
                                filterTable.Remove(descName); 
                                filterTable[origDesc.Name + suffix] = origDesc; 
                            }
                        } 
                        else
                        {
                            filterTable[descName] = desc;
                        } 
                    }
                    if (pipelineType == PIPELINE_PROPERTIES) 
                    { 
                        cacheResults = componentFilter.FilterProperties(component, filterTable);
                    } 
                    else
                    {
                        cacheResults = componentFilter.FilterEvents(component, filterTable);
                    } 
                    break;
 
                default: 
                    Debug.Fail("unknown pipeline type");
                    cacheResults = false; 
                    break;
            }

            // See if we can re-use the IList were were passed.  If we can, 
            // it is more efficient to re-use its slots than to generate new ones.
            // 
            if (list == null || list.IsReadOnly) 
            {
                Trace("Pipeline : Filter needs to create member list for {0}", instance.GetType().Name); 
                list = new ArrayList(filterTable.Values);
            }
            else
            { 
                list.Clear();
                foreach(object obj in filterTable.Values) 
                { 
                    list.Add(obj);
                } 
            }

            // Component filter has requested that we cache these
            // new changes.  We store them as a correctly typed collection 
            // so on successive invocations we can simply return.  Note that
            // we always return the IList so that successive stages in the 
            // pipeline can modify it. 
            //
            if (cacheResults && cache != null) 
            {
                ICollection cacheValue;

                switch(pipelineType) 
                {
                    case PIPELINE_ATTRIBUTES: 
                        Attribute[] attrArray = new Attribute[list.Count]; 
                        try
                        { 
                            list.CopyTo(attrArray, 0);
                        }
                        catch(InvalidCastException)
                        { 
                            throw new ArgumentException(SR.GetString(SR.TypeDescriptorExpectedElementType, typeof(Attribute).FullName));
                        } 
                        cacheValue = new AttributeCollection(attrArray); 
                        break;
 
                    case PIPELINE_PROPERTIES:
                        PropertyDescriptor[] propArray = new PropertyDescriptor[list.Count];
                        try
                        { 
                            list.CopyTo(propArray, 0);
                        } 
                        catch(InvalidCastException) 
                        {
                            throw new ArgumentException(SR.GetString(SR.TypeDescriptorExpectedElementType, typeof(PropertyDescriptor).FullName)); 
                        }
                        cacheValue = new PropertyDescriptorCollection(propArray, true);
                        break;
 
                    case PIPELINE_EVENTS:
                        EventDescriptor[] eventArray = new EventDescriptor[list.Count]; 
                        try 
                        {
                            list.CopyTo(eventArray, 0); 
                        }
                        catch(InvalidCastException)
                        {
                            throw new ArgumentException(SR.GetString(SR.TypeDescriptorExpectedElementType, typeof(EventDescriptor).FullName)); 
                        }
                        cacheValue = new EventDescriptorCollection(eventArray, true); 
                        break; 

                    default: 
                        Debug.Fail("unknown pipeline type");
                        cacheValue = null;
                        break;
                } 

                Trace("Pipeline : Filter results being cached for {0}", instance.GetType().Name); 
 
                FilterCacheItem cacheItem = new FilterCacheItem(componentFilter, cacheValue);
                cache[_pipelineFilterKeys[pipelineType]] = cacheItem; 
                cache.Remove(_pipelineAttributeFilterKeys[pipelineType]);
            }

            return list; 
        }
 
        ///  
        /// This is the first stage in the pipeline.  This checks the incoming member collection and if it
        /// differs from what we have seen in the past, it invalidates all successive pipelines. 
        /// 
        private static ICollection PipelineInitialize (int pipelineType, ICollection members, IDictionary cache) {
            if (cache != null) {
 
                bool cacheValid = true;
 
                ICollection cachedMembers = cache[_pipelineInitializeKeys[pipelineType]] as ICollection; 
                if (cachedMembers != null && cachedMembers.Count == members.Count) {
                    IEnumerator cacheEnum = cachedMembers.GetEnumerator(); 
                    IEnumerator memberEnum = members.GetEnumerator();

                    while(cacheEnum.MoveNext() && memberEnum.MoveNext()) {
                        if (cacheEnum.Current != memberEnum.Current) { 
                            cacheValid = false;
                            break; 
                        } 
                    }
                } 

                if (!cacheValid) {
                    // The cache wasn't valid.  Remove all subsequent cache layers
                    // and then save off new data. 
                    cache.Remove(_pipelineMergeKeys[pipelineType]);
                    cache.Remove(_pipelineFilterKeys[pipelineType]); 
                    cache.Remove(_pipelineAttributeFilterKeys[pipelineType]); 
                    cache[_pipelineInitializeKeys[pipelineType]] = members;
                } 
            }

            return members;
        } 

        ///  
        ///     Metadata merging is the second stage of our metadata pipeline.  This stage 
        ///     merges extended metdata with primary metadata, and stores it in
        ///     the cache if it is available. 
        /// 
        private static ICollection PipelineMerge(int pipelineType, ICollection primary, ICollection secondary, object instance, IDictionary cache)
        {
            // If there is no secondary collection, there is nothing to merge. 
            //
            if (secondary == null || secondary.Count == 0) 
            { 
                return primary;
            } 

            // Next, if we were given a cache, see if it has accurate data.
            //
            if (cache != null) 
            {
                ICollection mergeCache = cache[_pipelineMergeKeys[pipelineType]] as ICollection; 
                if (mergeCache != null && mergeCache.Count == (primary.Count + secondary.Count)) 
                {
                    // Walk the merge cache. 
                    IEnumerator mergeEnum = mergeCache.GetEnumerator();
                    IEnumerator primaryEnum = primary.GetEnumerator();
                    bool match = true;
 
                    while(primaryEnum.MoveNext() && mergeEnum.MoveNext())
                    { 
                        if (primaryEnum.Current != mergeEnum.Current) 
                        {
                            match = false; 
                            break;
                        }
                    }
 
                    if (match)
                    { 
                        IEnumerator secondaryEnum = secondary.GetEnumerator(); 

                        while(secondaryEnum.MoveNext() && mergeEnum.MoveNext()) 
                        {
                            if (secondaryEnum.Current != mergeEnum.Current)
                            {
                                match = false; 
                                break;
                            } 
                        } 
                    }
 
                    if (match)
                    {
                        return mergeCache;
                    } 
                }
            } 
 
            // Our cache didn't match.  We need to merge metadata and return
            // the merged copy.  We create an array list here, rather than 
            // an array, because we want successive sections of the
            // pipeline to be able to modify it.
            //
            ArrayList list = new ArrayList(primary.Count + secondary.Count); 
            foreach(object obj in primary)
            { 
                list.Add(obj); 
            }
            foreach(object obj in secondary) 
            {
                list.Add(obj);
            }
 
            if (cache != null)
            { 
                ICollection cacheValue; 

                switch(pipelineType) 
                {
                    case PIPELINE_ATTRIBUTES:
                        Attribute[] attrArray = new Attribute[list.Count];
                        list.CopyTo(attrArray, 0); 
                        cacheValue = new AttributeCollection(attrArray);
                        break; 
 
                    case PIPELINE_PROPERTIES:
                        PropertyDescriptor[] propArray = new PropertyDescriptor[list.Count]; 
                        list.CopyTo(propArray, 0);
                        cacheValue = new PropertyDescriptorCollection(propArray, true);
                        break;
 
                    case PIPELINE_EVENTS:
                        EventDescriptor[] eventArray = new EventDescriptor[list.Count]; 
                        list.CopyTo(eventArray, 0); 
                        cacheValue = new EventDescriptorCollection(eventArray, true);
                        break; 

                    default:
                        Debug.Fail("unknown pipeline type");
                        cacheValue = null; 
                        break;
                } 
 
                Trace("Pipeline : Merge results being cached for {0}", instance.GetType().Name);
                cache[_pipelineMergeKeys[pipelineType]] = cacheValue; 
                cache.Remove(_pipelineFilterKeys[pipelineType]);
                cache.Remove(_pipelineAttributeFilterKeys[pipelineType]);
            }
 
            return list;
        } 
 
        private static void RaiseRefresh(object component) {
            RefreshEventHandler handler = _refreshHandler; 

            if (handler != null)
            {
                handler(new RefreshEventArgs(component)); 
            }
        } 
 
        private static void RaiseRefresh(Type type) {
            RefreshEventHandler handler = _refreshHandler; 

            if (handler != null)
            {
                handler(new RefreshEventArgs(type)); 
            }
        } 
 
        /// 
        ///    Clears the properties and events for the specified 
        ///    component from the cache.
        /// 
        public static void Refresh(object component)
        { 
            #if DEBUG
            DebugTypeDescriptor.Refresh(component); 
            #endif 

            if (component == null) 
            {
                Debug.Fail("COMPAT:  Returning, but you should not pass null here");
                return;
            } 

            // Build up a list of type description providers for 
            // each type that is a derived type of the given 
            // object.  We will invalidate the metadata at
            // each of these levels. 

            Type type = component.GetType();
            bool found = false;
 
            lock(_providerTable)
            { 
                // ReflectTypeDescritionProvider is only bound to object, but we 
                // need go to through the entire table to try to find custom
                // providers.  If we find one, will clear our cache. 
                foreach(DictionaryEntry de in _providerTable)
                {
                    Type nodeType = de.Key as Type;
                    if (nodeType != null && type.IsAssignableFrom(nodeType) || nodeType == typeof(object)) 
                    {
                        TypeDescriptionNode node = (TypeDescriptionNode)de.Value; 
                        while(node != null && !(node.Provider is ReflectTypeDescriptionProvider)) 
                        {
                            found = true; 
                            node = node.Next;
                        }

                        if (node != null) 
                        {
                            ReflectTypeDescriptionProvider provider = (ReflectTypeDescriptionProvider)node.Provider; 
                            if (provider.IsPopulated(type)) 
                            {
                                found = true; 
                                provider.Refresh(type);
                            }
                        }
                    } 
                }
            } 
 
            // We need to clear our filter even if no typedescriptionprovider had data.
            // This is because if you call Refresh(instance1) and Refresh(instance2) 
            // and instance1 and instance2 are of the same type, you will end up not
            // actually deleting the dictionary cache on instance2 if you skip this
            // when you don't find a typedescriptionprovider.
            // However, we do not need to fire the event if we did not find any loaded 
            // typedescriptionprovider AND the cache is empty (if someone repeatedly calls
            // Refresh on an instance). 
 
            // Now, clear any cached data for the instance.
            // 
            IDictionary cache = GetCache(component);
            if (found || cache!= null)
            {
                if (cache != null) 
                {
                    Trace("Pipeline : Refresh clearing all pipeline caches"); 
                    for (int idx = 0; idx < _pipelineFilterKeys.Length; idx++) 
                    {
                        cache.Remove(_pipelineFilterKeys[idx]); 
                        cache.Remove(_pipelineMergeKeys[idx]);
                        cache.Remove(_pipelineAttributeFilterKeys[idx]);
                    }
 
                }
 
                Interlocked.Increment(ref _metadataVersion); 

                // And raise the event. 
                //
                RaiseRefresh(component);
            }
        } 

        ///  
        ///    Clears the properties and events for the specified type 
        ///    of component from the cache.
        ///  
        public static void Refresh(Type type)
        {
            #if DEBUG
            DebugTypeDescriptor.Refresh(type); 
            #endif
 
            if (type == null) 
            {
                Debug.Fail("COMPAT:  Returning, but you should not pass null here"); 
                return;
            }

            // Build up a list of type description providers for 
            // each type that is a derived type of the given
            // type.  We will invalidate the metadata at 
            // each of these levels. 

            bool found = false; 

            lock(_providerTable)
            {
                // ReflectTypeDescritionProvider is only bound to object, but we 
                // need go to through the entire table to try to find custom
                // providers.  If we find one, will clear our cache. 
                foreach(DictionaryEntry de in _providerTable) 
                {
                    Type nodeType = de.Key as Type; 
                    if (nodeType != null && type.IsAssignableFrom(nodeType) || nodeType == typeof(object))
                    {
                        TypeDescriptionNode node = (TypeDescriptionNode)de.Value;
                        while(node != null && !(node.Provider is ReflectTypeDescriptionProvider)) 
                        {
                            found = true; 
                            node = node.Next; 
                        }
 
                        if (node != null)
                        {
                            ReflectTypeDescriptionProvider provider = (ReflectTypeDescriptionProvider)node.Provider;
                            if (provider.IsPopulated(type)) 
                            {
                                found = true; 
                                provider.Refresh(type); 
                            }
                        } 
                    }
                }
            }
 
            // We only clear our filter and fire the refresh event if there was one or
            // more type description providers that were populated with metdata. 
            // This prevents us from doing a lot of extra work and raising 
            // a ton more events than we need to.
            // 
            if (found)
            {
                Interlocked.Increment(ref _metadataVersion);
 
                // And raise the event.
                // 
                RaiseRefresh(type); 
            }
        } 

        /// 
        ///    Clears the properties and events for the specified
        ///    module from the cache. 
        /// 
        public static void Refresh(Module module) 
        { 
            #if DEBUG
            DebugTypeDescriptor.Refresh(module); 
            #endif

            if (module == null)
            { 
                Debug.Fail("COMPAT:  Returning, but you should not pass null here");
                return; 
            } 

            // Build up a list of type description providers for 
            // each type that is a derived type of the given
            // object.  We will invalidate the metadata at
            // each of these levels.
            Hashtable refreshedTypes = null; 

            lock(_providerTable) 
            { 
                foreach(DictionaryEntry de in _providerTable)
                { 
                    Type nodeType = de.Key as Type;
                    if (nodeType != null && nodeType.Module.Equals(module) || nodeType == typeof(object))
                    {
                        TypeDescriptionNode node = (TypeDescriptionNode)de.Value; 
                        while(node != null && !(node.Provider is ReflectTypeDescriptionProvider))
                        { 
                            if (refreshedTypes == null) { 
                                refreshedTypes = new Hashtable();
                            } 
                            refreshedTypes[nodeType] = nodeType;
                            node = node.Next;
                        }
 
                        if (node != null)
                        { 
                            ReflectTypeDescriptionProvider provider = (ReflectTypeDescriptionProvider)node.Provider; 
                            Type[] populatedTypes = provider.GetPopulatedTypes(module);
 
                            foreach(Type populatedType in populatedTypes) {
                                provider.Refresh(populatedType);
                                if (refreshedTypes == null) {
                                    refreshedTypes = new Hashtable(); 
                                }
                                refreshedTypes[populatedType] = populatedType; 
                            } 
                        }
                    } 
                }
            }

            // And raise the event if types were refresh and handlers are attached. 
            //
            if (refreshedTypes != null && _refreshHandler != null) 
            { 
                foreach(Type t in refreshedTypes.Keys) {
                    RaiseRefresh(t); 
                }
            }
        }
 
        /// 
        ///    Clears the properties and events for the specified 
        ///    assembly from the cache. 
        /// 
        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Machine | ResourceScope.Assembly, ResourceScope.Machine | ResourceScope.Assembly)]
        public static void Refresh(Assembly assembly)
        {
            if (assembly == null) 
            {
                Debug.Fail("COMPAT:  Returning, but you should not pass null here"); 
                return; 
            }
 
            foreach (Module mod in assembly.GetModules())
            {
                Refresh(mod);
            } 

            // Debug type descriptor has the same code, so our call above will handle this. 
        } 

        ///  
        ///     The RemoveAssociation method removes an association with an object.
        /// 
        [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        public static void RemoveAssociation(object primary, object secondary)
        { 
            if (primary == null) 
            {
                throw new ArgumentNullException("primary"); 
            }

            if (secondary == null)
            { 
                throw new ArgumentNullException("secondary");
            } 
 
            Hashtable assocTable = _associationTable;
            if (assocTable != null) 
            {
                IList associations = (IList)assocTable[primary];
                if (associations != null)
                { 
                    lock(associations)
                    { 
                        for (int idx = associations.Count - 1; idx >= 0; idx--) 
                        {
                            // Look for an associated object that has a type that 
                            // matches the given type.
                            //
                            WeakReference weakRef = (WeakReference)associations[idx];
                            object secondaryItem = weakRef.Target; 
                            if (secondaryItem == null || secondaryItem == secondary)
                            { 
                                associations.RemoveAt(idx); 
                            }
                        } 
                    }
                }
            }
        } 

        ///  
        ///     The RemoveAssociations method removes all associations for a primary object. 
        /// 
        [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")] 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static void RemoveAssociations(object primary)
        {
            if (primary == null) 
            {
                throw new ArgumentNullException("primary"); 
            } 

            Hashtable assocTable = _associationTable; 
            if (assocTable != null)
            {
                assocTable.Remove(primary);
            } 
        }
 
        ///  
        ///     The RemoveProvider method removes a previously added type
        ///     description provider.  Removing a provider causes a Refresh 
        ///     event to be raised for the object or type the provider is
        ///     associated with.
        /// 
        [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")] 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static void RemoveProvider(TypeDescriptionProvider provider, Type type) 
        { 
            if (provider == null)
            { 
                throw new ArgumentNullException("provider");
            }

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

            // Walk the nodes until we find the right one, and then remove it. 
            NodeRemove(type, provider);
            RaiseRefresh(type);
        }
 
        /// 
        ///     The RemoveProvider method removes a previously added type 
        ///     description provider.  Removing a provider causes a Refresh 
        ///     event to be raised for the object or type the provider is
        ///     associated with. 
        /// 
        [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static void RemoveProvider(TypeDescriptionProvider provider, object instance) 
        {
            if (provider == null) 
            { 
                throw new ArgumentNullException("provider");
            } 

            if (instance == null)
            {
                throw new ArgumentNullException("instance"); 
            }
 
            // Walk the nodes until we find the right one, and then remove it. 
            NodeRemove(instance, provider);
            RaiseRefresh(instance); 
        }

        /// 
        ///     This function takes a member descriptor and an attribute and determines whether 
        ///     the member satisfies the particular attribute.  This either means that the member
        ///     contains the attribute or the member does not contain the attribute and the default 
        ///     for the attribute matches the passed in attribute. 
        /// 
        private static bool ShouldHideMember(MemberDescriptor member, Attribute attribute) 
        {
            if (member == null || attribute == null)
            {
                return true; 
            }
 
            Attribute memberAttribute = member.Attributes[attribute.GetType()]; 
            if (memberAttribute == null)
            { 
                return !attribute.IsDefaultAttribute();
            }
            else
            { 
                return !(attribute.Match(memberAttribute));
            } 
        } 

        ///  
        ///     Sorts descriptors by name of the descriptor.
        /// 
        public static void SortDescriptorArray(IList infos)
        { 
            if (infos == null)
            { 
                throw new ArgumentNullException("infos"); 
            }
 
            ArrayList.Adapter(infos).Sort(MemberDescriptorComparer.Instance);
        }

        ///  
        ///     Internal tracing API for debugging type descriptor.
        ///  
        [Conditional("DEBUG")] 
        internal static void Trace(string message, params object[] args)
        { 
            Debug.WriteLineIf(TraceDescriptor.Enabled, string.Format(CultureInfo.InvariantCulture, "TypeDescriptor : {0}", string.Format(CultureInfo.InvariantCulture, message, args)));
        }

        ///  
        ///     This is a type description provider that adds the given
        ///     array of attributes to a class or instance, preserving the rest 
        ///     of the metadata in the process. 
        /// 
        private sealed class AttributeProvider : TypeDescriptionProvider 
        {
            Attribute[] _attrs;

            ///  
            ///     Creates a new attribute provider.
            ///  
            internal AttributeProvider(TypeDescriptionProvider existingProvider, params Attribute[] attrs) : base(existingProvider) 
            {
                _attrs = attrs; 
            }

            /// 
            ///     Creates a custom type descriptor that replaces the attributes. 
            /// 
            public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance) 
            { 
                return new AttributeTypeDescriptor(_attrs, base.GetTypeDescriptor(objectType, instance));
            } 

            /// 
            ///     Our custom type descriptor.
            ///  
            private class AttributeTypeDescriptor : CustomTypeDescriptor
            { 
                Attribute[]         _attributeArray; 

                ///  
                ///     Creates a new custom type descriptor that can merge
                ///     the provided set of attributes with the existing set.
                /// 
                internal AttributeTypeDescriptor(Attribute[] attrs, ICustomTypeDescriptor parent) : base(parent) 
                {
                    _attributeArray = attrs; 
                } 

                ///  
                ///     Retrieves the merged set of attributes.  We do not cache
                ///     this because there is always the possibility that someone
                ///     changed our parent provider's metadata.  TypeDescriptor
                ///     will cache this for us anyhow. 
                /// 
                public override AttributeCollection GetAttributes() 
                { 
                    Attribute[] finalAttr = null;
                    AttributeCollection existing = base.GetAttributes(); 
                    Attribute[] newAttrs = _attributeArray;
                    Attribute[] newArray = new Attribute[existing.Count + newAttrs.Length];
                    int actualCount = existing.Count;
                    existing.CopyTo(newArray, 0); 

                    for (int idx = 0; idx < newAttrs.Length; idx++) 
                    { 

                        Debug.Assert(newAttrs[idx] != null, "_attributes contains a null member"); 

                        // We must see if this attribute is already in the existing
                        // array.  If it is, we replace it.
                        bool match = false; 
                        for (int existingIdx = 0; existingIdx < existing.Count; existingIdx++)
                        { 
                            if (newArray[existingIdx].TypeId.Equals(newAttrs[idx].TypeId)) 
                            {
                                match = true; 
                                newArray[existingIdx] = newAttrs[idx];
                                break;
                            }
                        } 

                        if (!match) 
                        { 
                            newArray[actualCount++] = newAttrs[idx];
                        } 
                    }

                    // Now, if we collapsed some attributes, create a new array.
                    // 
                    if (actualCount < newArray.Length)
                    { 
                        finalAttr = new Attribute[actualCount]; 
                        Array.Copy(newArray, 0, finalAttr, 0, actualCount);
                    } 
                    else
                    {
                        finalAttr= newArray;
                    } 

                    return new AttributeCollection(finalAttr); 
                } 
            }
        } 

        /// 
        ///     This class is a type description provider that works with the IComNativeDescriptorHandler
        ///     interface. 
        /// 
        private sealed class ComNativeDescriptionProvider : TypeDescriptionProvider 
        { 
#pragma warning disable 618
            private IComNativeDescriptorHandler _handler; 

            internal ComNativeDescriptionProvider(IComNativeDescriptorHandler handler)
            {
                _handler = handler; 
            }
 
            ///  
            ///     Returns the COM handler object.
            ///  
            internal IComNativeDescriptorHandler Handler
            {
                get
                { 
                    return _handler;
                } 
                set 
                {
                    _handler = value; 
                }
            }
#pragma warning restore 618
 
            /// 
            ///     Implements GetTypeDescriptor.  This creates a custom type 
            ///     descriptor that walks the linked list for each of its calls. 
            /// 
 
            [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters")]
            public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
            {
                if (objectType == null) 
                {
                    throw new ArgumentNullException("objectType"); 
                } 

                if (instance == null) 
                {
                    return null;
                }
 
                if (!objectType.IsInstanceOfType(instance))
                { 
                    throw new ArgumentException("instance"); 
                }
 
                return new ComNativeTypeDescriptor(_handler, instance);
            }

            ///  
            ///     This type descriptor sits on top of a native
            ///     descriptor handler. 
            ///  
            private sealed class ComNativeTypeDescriptor : ICustomTypeDescriptor
            { 
#pragma warning disable 618
                private IComNativeDescriptorHandler _handler;
                private object _instance;
 
                /// 
                ///     Creates a new ComNativeTypeDescriptor. 
                ///  
                internal ComNativeTypeDescriptor(IComNativeDescriptorHandler handler, object instance)
                { 
                    _handler = handler;
                    _instance = instance;
                }
#pragma warning restore 618 

                ///  
                ///     ICustomTypeDescriptor implementation. 
                /// 
                AttributeCollection ICustomTypeDescriptor.GetAttributes() 
                {
                    return _handler.GetAttributes(_instance);
                }
 
                /// 
                ///     ICustomTypeDescriptor implementation. 
                ///  
                string ICustomTypeDescriptor.GetClassName()
                { 
                    return _handler.GetClassName(_instance);
                }

                ///  
                ///     ICustomTypeDescriptor implementation.
                ///  
                string ICustomTypeDescriptor.GetComponentName() 
                {
                    return null; 
                }

                /// 
                ///     ICustomTypeDescriptor implementation. 
                /// 
                TypeConverter ICustomTypeDescriptor.GetConverter() 
                { 
                    return _handler.GetConverter(_instance);
                } 

                /// 
                ///     ICustomTypeDescriptor implementation.
                ///  
                EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
                { 
                    return _handler.GetDefaultEvent(_instance); 
                }
 
                /// 
                ///     ICustomTypeDescriptor implementation.
                /// 
                PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() 
                {
                    return _handler.GetDefaultProperty(_instance); 
                } 

                ///  
                ///     ICustomTypeDescriptor implementation.
                /// 
                object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
                { 
                    return _handler.GetEditor(_instance, editorBaseType);
                } 
 
                /// 
                ///     ICustomTypeDescriptor implementation. 
                /// 
                EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
                {
                    return _handler.GetEvents(_instance); 
                }
 
                ///  
                ///     ICustomTypeDescriptor implementation.
                ///  
                EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
                {
                    return _handler.GetEvents(_instance, attributes);
                } 

                ///  
                ///     ICustomTypeDescriptor implementation. 
                /// 
                PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() 
                {
                    return _handler.GetProperties(_instance, null);
                }
 
                /// 
                ///     ICustomTypeDescriptor implementation. 
                ///  
                PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
                { 
                    return _handler.GetProperties(_instance, attributes);
                }

                ///  
                ///     ICustomTypeDescriptor implementation.
                ///  
                object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd) 
                {
                    return _instance; 
                }
            }
        }
 
        /// 
        ///     This is a simple class that is used to store a filtered 
        ///     set of members in an object's dictionary cache.  It is 
        ///     used by the PipelineAttributeFilter method.
        ///  
        private sealed class AttributeFilterCacheItem
        {
            private Attribute[] _filter;
            internal ICollection FilteredMembers; 

            internal AttributeFilterCacheItem(Attribute[] filter, ICollection filteredMembers) 
            { 
                _filter = filter;
                FilteredMembers = filteredMembers; 
            }

            internal bool IsValid(Attribute[] filter)
            { 
                if (_filter.Length != filter.Length) return false;
 
                for (int idx = 0; idx < filter.Length; idx++) { 
                    if (_filter[idx] != filter[idx]) {
                        return false; 
                    }
                }

                return true; 
            }
        } 
 
        /// 
        /// This small class contains cache information for the filter stage of our 
        /// caching algorithm.  It is used by the PipelineFilter method.
        /// 
        private sealed class FilterCacheItem {
            private ITypeDescriptorFilterService _filterService; 
            internal ICollection FilteredMembers;
 
            internal FilterCacheItem(ITypeDescriptorFilterService filterService, ICollection filteredMembers) { 
                _filterService = filterService;
                FilteredMembers = filteredMembers; 
            }

            internal bool IsValid(ITypeDescriptorFilterService filterService) {
                if (!Object.ReferenceEquals(_filterService, filterService)) return false; 
                return true;
            } 
        } 

        ///  
        ///     An unimplemented interface.  What is this?  It is an interface that nobody ever
        ///     implements, of course? Where and why would it be used?  Why, to find cross-process
        ///     remoted objects, of course!  If a well-known object comes in from a cross process
        ///     connection, the remoting layer does contain enough type information to determine 
        ///     if an object implements an interface.  It assumes that if you are going to cast
        ///     an object to an interface that you know what you're doing, and allows the cast, 
        ///     even for objects that DON'T actually implement the interface.  The error here 
        ///     is raised later when you make your first call on that interface pointer:  you
        ///     get a remoting exception. 
        ///
        ///     This is a big problem for code that does "is" and "as" checks to detect the
        ///     presence of an interface.  We do that all over the place here, so we do a check
        ///     during parameter validation to see if an object implements IUnimplemented.  If it 
        ///     does, we know that what we really have is a lying remoting proxy, and we bail.
        ///  
        private interface IUnimplemented {} 

        ///  
        ///     This comparer compares member descriptors for sorting.
        /// 
        private sealed class MemberDescriptorComparer : IComparer {
            public static readonly MemberDescriptorComparer Instance = new MemberDescriptorComparer(); 

            public int Compare(object left, object right) { 
                return string.Compare(((MemberDescriptor)left).Name, ((MemberDescriptor)right).Name, false, CultureInfo.InvariantCulture); 
            }
        } 

        /// 
        ///     This is a merged type descriptor that can merge the output of
        ///     a primary and secondary type descriptor.  If the primary doesn't 
        ///     provide the needed information, the request is passed on to the
        ///     secondary. 
        ///  
        private sealed class MergedTypeDescriptor : ICustomTypeDescriptor
        { 
            private ICustomTypeDescriptor _primary;
            private ICustomTypeDescriptor _secondary;

            ///  
            ///     Creates a new MergedTypeDescriptor.
            ///  
            internal MergedTypeDescriptor(ICustomTypeDescriptor primary, ICustomTypeDescriptor secondary) 
            {
                _primary = primary; 
                _secondary = secondary;
            }

            ///  
            ///     ICustomTypeDescriptor implementation.
            ///  
            AttributeCollection ICustomTypeDescriptor.GetAttributes() 
            {
                AttributeCollection attrs = _primary.GetAttributes(); 
                if (attrs == null)
                {
                    attrs = _secondary.GetAttributes();
                } 

                Debug.Assert(attrs != null, "Someone should have handled this"); 
                return attrs; 
            }
 
            /// 
            ///     ICustomTypeDescriptor implementation.
            /// 
            string ICustomTypeDescriptor.GetClassName() 
            {
                string className = _primary.GetClassName(); 
                if (className == null) 
                {
                    className = _secondary.GetClassName(); 
                }

                Debug.Assert(className != null, "Someone should have handled this");
                return className; 
            }
 
            ///  
            ///     ICustomTypeDescriptor implementation.
            ///  
            string ICustomTypeDescriptor.GetComponentName()
            {
                string name = _primary.GetComponentName();
                if (name == null) 
                {
                    name = _secondary.GetComponentName(); 
                } 

                return name; 
            }

            /// 
            ///     ICustomTypeDescriptor implementation. 
            /// 
            TypeConverter ICustomTypeDescriptor.GetConverter() 
            { 
                TypeConverter converter = _primary.GetConverter();
                if (converter == null) 
                {
                    converter = _secondary.GetConverter();
                }
 
                Debug.Assert(converter != null, "Someone should have handled this");
                return converter; 
            } 

            ///  
            ///     ICustomTypeDescriptor implementation.
            /// 
            EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
            { 
                EventDescriptor evt = _primary.GetDefaultEvent();
                if (evt == null) 
                { 
                    evt = _secondary.GetDefaultEvent();
                } 

                return evt;
            }
 
            /// 
            ///     ICustomTypeDescriptor implementation. 
            ///  
            PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
            { 
                PropertyDescriptor prop = _primary.GetDefaultProperty();
                if (prop == null)
                {
                    prop = _secondary.GetDefaultProperty(); 
                }
 
                return prop; 
            }
 
            /// 
            ///     ICustomTypeDescriptor implementation.
            /// 
            object ICustomTypeDescriptor.GetEditor(Type editorBaseType) 
            {
                if (editorBaseType == null) 
                { 
                    throw new ArgumentNullException("editorBaseType");
                } 

                object editor = _primary.GetEditor(editorBaseType);
                if (editor == null)
                { 
                    editor = _secondary.GetEditor(editorBaseType);
                } 
 
                return editor;
            } 

            /// 
            ///     ICustomTypeDescriptor implementation.
            ///  
            EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
            { 
                EventDescriptorCollection events = _primary.GetEvents(); 
                if (events == null)
                { 
                    events = _secondary.GetEvents();
                }

                Debug.Assert(events != null, "Someone should have handled this"); 
                return events;
            } 
 
            /// 
            ///     ICustomTypeDescriptor implementation. 
            /// 
            EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
            {
                EventDescriptorCollection events = _primary.GetEvents(attributes); 
                if (events == null)
                { 
                    events = _secondary.GetEvents(attributes); 
                }
 
                Debug.Assert(events != null, "Someone should have handled this");
                return events;
            }
 
            /// 
            ///     ICustomTypeDescriptor implementation. 
            ///  
            PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
            { 
                PropertyDescriptorCollection properties = _primary.GetProperties();
                if (properties == null)
                {
                    properties = _secondary.GetProperties(); 
                }
 
                Debug.Assert(properties != null, "Someone should have handled this"); 
                return properties;
            } 

            /// 
            ///     ICustomTypeDescriptor implementation.
            ///  
            PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
            { 
                PropertyDescriptorCollection properties = _primary.GetProperties(attributes); 
                if (properties == null)
                { 
                    properties = _secondary.GetProperties(attributes);
                }

                Debug.Assert(properties != null, "Someone should have handled this"); 
                return properties;
            } 
 
            /// 
            ///     ICustomTypeDescriptor implementation. 
            /// 
            object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
            {
                object owner = _primary.GetPropertyOwner(pd); 
                if (owner == null)
                { 
                    owner = _secondary.GetPropertyOwner(pd); 
                }
 
                return owner;
            }
        }
 
        /// 
        ///     This is a linked list node that is comprised of a type 
        ///     description provider.  Each node contains a Next pointer 
        ///     to the next node in the list and also a Provider pointer
        ///     which contains the type description provider this node 
        ///     represents.  The implementation of TypeDescriptionProvider
        ///     that the node provides simply invokes the corresponding
        ///     method on the node's provider.
        ///  
        private sealed class TypeDescriptionNode : TypeDescriptionProvider
        { 
            internal TypeDescriptionNode                Next; 
            internal TypeDescriptionProvider   Provider;
 
            /// 
            ///     Creates a new type description node.
            /// 
            internal TypeDescriptionNode(TypeDescriptionProvider provider) 
            {
                Provider = provider; 
            } 

            ///  
            ///     Implements CreateInstance.  This just walks the linked list
            ///     looking for someone who implements the call.
            /// 
            public override object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args) 
            {
                if (objectType == null) 
                { 
                    throw new ArgumentNullException("objectType");
                } 

                if (argTypes != null)
                {
                    if (args == null) 
                    {
                        throw new ArgumentNullException("args"); 
                    } 

                    if (argTypes.Length != args.Length) 
                    {
                        throw new ArgumentException(SR.GetString(SR.TypeDescriptorArgsCountMismatch));
                    }
                } 

                return Provider.CreateInstance(provider, objectType, argTypes, args); 
            } 

            ///  
            ///     Implements GetCache.  This just walks the linked
            ///     list looking for someone who implements the call.
            /// 
            public override IDictionary GetCache(object instance) 
            {
                if (instance == null) 
                { 
                    throw new ArgumentNullException("instance");
                } 

                return Provider.GetCache(instance);
            }
 
            /// 
            ///     Implements GetExtendedTypeDescriptor.  This creates a custom type 
            ///     descriptor that walks the linked list for each of its calls. 
            /// 
            public override ICustomTypeDescriptor GetExtendedTypeDescriptor(object instance) 
            {
                if (instance == null)
                {
                    throw new ArgumentNullException("instance"); 
                }
 
                return new DefaultExtendedTypeDescriptor(this, instance); 
            }
 
            /// 
            ///     The name of the specified component, or null if the component has no name.
            ///     In many cases this will return the same value as GetComponentName. If the
            ///     component resides in a nested container or has other nested semantics, it may 
            ///     return a different fully qualfied name.
            /// 
            ///     If not overridden, the default implementation of this method will call 
            ///     GetTypeDescriptor.GetComponentName.
            ///  
            public override string GetFullComponentName(object component)
            {
                if (component == null)
                { 
                    throw new ArgumentNullException("component");
                } 
 
                return Provider.GetFullComponentName(component);
            } 

            /// 
            ///     Implements GetReflectionType.  This just walks the linked list
            ///     looking for someone who implements the call. 
            /// 
            public override Type GetReflectionType(Type objectType, object instance) 
            { 
                if (objectType == null)
                { 
                    throw new ArgumentNullException("objectType");
                }

                return Provider.GetReflectionType(objectType, instance); 
            }
 
            ///  
            ///     Implements GetTypeDescriptor.  This creates a custom type
            ///     descriptor that walks the linked list for each of its calls. 
            /// 

            [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters")]
            public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance) 
            {
                if (objectType == null) 
                { 
                    throw new ArgumentNullException("objectType");
                } 

                if (instance != null && !objectType.IsInstanceOfType(instance))
                {
                    throw new ArgumentException("instance"); 
                }
 
                return new DefaultTypeDescriptor(this, objectType, instance); 
            }
 
            /// 
            ///     A type descriptor for extended types.  This type descriptor
            ///     looks at the head node in the linked list.
            ///  
            private struct DefaultExtendedTypeDescriptor : ICustomTypeDescriptor
            { 
                private TypeDescriptionNode _node; 
                private object              _instance;
 
                /// 
                ///     Creates a new WalkingExtendedTypeDescriptor.
                /// 
                internal DefaultExtendedTypeDescriptor(TypeDescriptionNode node, object instance) 
                {
                    _node = node; 
                    _instance = instance; 
                }
 
                /// 
                ///     ICustomTypeDescriptor implementation.
                /// 
                AttributeCollection ICustomTypeDescriptor.GetAttributes() 
                {
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider. 
                    // If so, we can call on it directly rather than creating another 
                    // custom type descriptor
 
                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;

                    if (rp != null) { 
                        return rp.GetExtendedAttributes(_instance);
                    } 
 
                    ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
                    if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor")); 
                    AttributeCollection attrs = desc.GetAttributes();
                    if (attrs == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetAttributes"));
                    return attrs;
                } 

                ///  
                ///     ICustomTypeDescriptor implementation. 
                /// 
                string ICustomTypeDescriptor.GetClassName() 
                {
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another
                    // custom type descriptor 

                    TypeDescriptionProvider p = _node.Provider; 
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider; 

                    if (rp != null) { 
                        return rp.GetExtendedClassName(_instance);
                    }

                    ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance); 
                    if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
                    string name = desc.GetClassName(); 
                    if (name == null) name = _instance.GetType().FullName; 
                    return name;
                } 

                /// 
                ///     ICustomTypeDescriptor implementation.
                ///  
                string ICustomTypeDescriptor.GetComponentName()
                { 
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider. 
                    // If so, we can call on it directly rather than creating another
                    // custom type descriptor 

                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
 
                    if (rp != null) {
                        return rp.GetExtendedComponentName(_instance); 
                    } 

                    ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance); 
                    if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
                    return desc.GetComponentName();
                }
 
                /// 
                ///     ICustomTypeDescriptor implementation. 
                ///  
                TypeConverter ICustomTypeDescriptor.GetConverter()
                { 
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another
                    // custom type descriptor
 
                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider; 
 
                    if (rp != null) {
                        return rp.GetExtendedConverter(_instance); 
                    }

                    ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
                    if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor")); 
                    TypeConverter converter = desc.GetConverter();
                    if (converter == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetConverter")); 
                    return converter; 
                }
 
                /// 
                ///     ICustomTypeDescriptor implementation.
                /// 
                EventDescriptor ICustomTypeDescriptor.GetDefaultEvent() 
                {
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider. 
                    // If so, we can call on it directly rather than creating another 
                    // custom type descriptor
 
                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;

                    if (rp != null) { 
                        return rp.GetExtendedDefaultEvent(_instance);
                    } 
 
                    ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
                    if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor")); 
                    return desc.GetDefaultEvent();
                }

                ///  
                ///     ICustomTypeDescriptor implementation.
                ///  
                PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() 
                {
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider. 
                    // If so, we can call on it directly rather than creating another
                    // custom type descriptor

                    TypeDescriptionProvider p = _node.Provider; 
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
 
                    if (rp != null) { 
                        return rp.GetExtendedDefaultProperty(_instance);
                    } 

                    ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
                    if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
                    return desc.GetDefaultProperty(); 
                }
 
                ///  
                ///     ICustomTypeDescriptor implementation.
                ///  
                object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
                {
                    if (editorBaseType == null)
                    { 
                        throw new ArgumentNullException("editorBaseType");
                    } 
 
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another 
                    // custom type descriptor

                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider; 

                    if (rp != null) { 
                        return rp.GetExtendedEditor(_instance, editorBaseType); 
                    }
 
                    ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
                    if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
                    return desc.GetEditor(editorBaseType);
                } 

                ///  
                ///     ICustomTypeDescriptor implementation. 
                /// 
                EventDescriptorCollection ICustomTypeDescriptor.GetEvents() 
                {
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another
                    // custom type descriptor 

                    TypeDescriptionProvider p = _node.Provider; 
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider; 

                    if (rp != null) { 
                        return rp.GetExtendedEvents(_instance);
                    }

                    ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance); 
                    if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
                    EventDescriptorCollection events = desc.GetEvents(); 
                    if (events == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetEvents")); 
                    return events;
                } 

                /// 
                ///     ICustomTypeDescriptor implementation.
                ///  
                EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
                { 
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider. 
                    // If so, we can call on it directly rather than creating another
                    // custom type descriptor 

                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
 
                    if (rp != null) {
                        // There is no need to filter these events.  For extended objects, they 
                        // are accessed through our pipeline code, which always filters before 
                        // returning.  So any filter we do here is redundant.  Note that we do
                        // pass a valid filter to a custom descriptor so it can optimize if it wants. 
                        EventDescriptorCollection events = rp.GetExtendedEvents(_instance);
                        return events;
                    }
 
                    ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
                    if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor")); 
                    EventDescriptorCollection evts = desc.GetEvents(attributes); 
                    if (evts == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetEvents"));
                    return evts; 
                }

                /// 
                ///     ICustomTypeDescriptor implementation. 
                /// 
                PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() 
                { 
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another 
                    // custom type descriptor

                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider; 

                    if (rp != null) { 
                        return rp.GetExtendedProperties(_instance); 
                    }
 
                    ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
                    if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
                    PropertyDescriptorCollection properties = desc.GetProperties();
                    if (properties == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetProperties")); 
                    return properties;
                } 
 
                /// 
                ///     ICustomTypeDescriptor implementation. 
                /// 
                PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
                {
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider. 
                    // If so, we can call on it directly rather than creating another
                    // custom type descriptor 
 
                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider; 

                    if (rp != null) {
                        // There is no need to filter these properties.  For extended objects, they
                        // are accessed through our pipeline code, which always filters before 
                        // returning.  So any filter we do here is redundant.  Note that we do
                        // pass a valid filter to a custom descriptor so it can optimize if it wants. 
                        PropertyDescriptorCollection props = rp.GetExtendedProperties(_instance); 
                        return props;
                    } 

                    ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
                    if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
                    PropertyDescriptorCollection properties = desc.GetProperties(attributes); 
                    if (properties == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetProperties"));
                    return properties; 
                } 

                ///  
                ///     ICustomTypeDescriptor implementation.
                /// 
                object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
                { 
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another 
                    // custom type descriptor 

                    TypeDescriptionProvider p = _node.Provider; 
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;

                    if (rp != null) {
                        return rp.GetExtendedPropertyOwner(_instance, pd); 
                    }
 
                    ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance); 
                    if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
                    object owner = desc.GetPropertyOwner(pd); 
                    if (owner == null) owner = _instance;
                    return owner;
                }
            } 

            ///  
            ///     The default type descriptor. 
            /// 
            private struct DefaultTypeDescriptor : ICustomTypeDescriptor 
            {
                private TypeDescriptionNode _node;
                private Type                _objectType;
                private object              _instance; 

                ///  
                ///     Creates a new WalkingTypeDescriptor. 
                /// 
                internal DefaultTypeDescriptor(TypeDescriptionNode node, Type objectType, object instance) 
                {
                    _node = node;
                    _objectType = objectType;
                    _instance = instance; 
                }
 
                ///  
                ///     ICustomTypeDescriptor implementation.
                ///  
                AttributeCollection ICustomTypeDescriptor.GetAttributes()
                {
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another 
                    // custom type descriptor
 
                    TypeDescriptionProvider p = _node.Provider; 
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
                    AttributeCollection attrs; 

                    if (rp != null) {
                        attrs = rp.GetAttributes(_objectType);
                    } 
                    else {
                        ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance); 
                        if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor")); 
                        attrs = desc.GetAttributes();
                        if (attrs == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetAttributes")); 
                    }

                    return attrs;
                } 

                ///  
                ///     ICustomTypeDescriptor implementation. 
                /// 
                string ICustomTypeDescriptor.GetClassName() 
                {
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another
                    // custom type descriptor 

                    TypeDescriptionProvider p = _node.Provider; 
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider; 
                    string name;
 
                    if (rp != null) {
                        name = rp.GetClassName(_objectType);
                    }
                    else { 
                        ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
                        if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor")); 
                        name = desc.GetClassName(); 
                        if (name == null) name = _objectType.FullName;
                    } 

                    return name;
                }
 
                /// 
                ///     ICustomTypeDescriptor implementation. 
                ///  
                string ICustomTypeDescriptor.GetComponentName()
                { 
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another
                    // custom type descriptor
 
                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider; 
                    string name; 

                    if (rp != null) { 
                        name = rp.GetComponentName(_objectType, _instance);
                    }
                    else {
                        ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance); 
                        if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
                        name = desc.GetComponentName(); 
                    } 

                    return name; 
                }

                /// 
                ///     ICustomTypeDescriptor implementation. 
                /// 
                TypeConverter ICustomTypeDescriptor.GetConverter() 
                { 
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another 
                    // custom type descriptor

                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider; 
                    TypeConverter converter;
 
                    if (rp != null) { 
                        converter = rp.GetConverter(_objectType, _instance);
                    } 
                    else {
                        ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
                        if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
                        converter = desc.GetConverter(); 
                        if (converter == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetConverter"));
                    } 
 
                    return converter;
                } 

                /// 
                ///     ICustomTypeDescriptor implementation.
                ///  
                EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
                { 
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider. 
                    // If so, we can call on it directly rather than creating another
                    // custom type descriptor 

                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
                    EventDescriptor defaultEvent; 

                    if (rp != null) { 
                        defaultEvent = rp.GetDefaultEvent(_objectType, _instance); 
                    }
                    else { 
                        ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
                        if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
                        defaultEvent = desc.GetDefaultEvent();
                    } 

                    return defaultEvent; 
                } 

                ///  
                ///     ICustomTypeDescriptor implementation.
                /// 
                PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
                { 
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another 
                    // custom type descriptor 

                    TypeDescriptionProvider p = _node.Provider; 
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
                    PropertyDescriptor defaultProperty;

                    if (rp != null) { 
                        defaultProperty = rp.GetDefaultProperty(_objectType, _instance);
                    } 
                    else { 
                        ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
                        if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor")); 
                        defaultProperty = desc.GetDefaultProperty();
                    }

                    return defaultProperty; 
                }
 
                ///  
                ///     ICustomTypeDescriptor implementation.
                ///  
                object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
                {
                    if (editorBaseType == null)
                    { 
                        throw new ArgumentNullException("editorBaseType");
                    } 
 
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another 
                    // custom type descriptor

                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider; 
                    object editor;
 
                    if (rp != null) { 
                        editor = rp.GetEditor(_objectType, _instance, editorBaseType);
                    } 
                    else {
                        ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
                        if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
                        editor = desc.GetEditor(editorBaseType); 
                    }
 
                    return editor; 
                }
 
                /// 
                ///     ICustomTypeDescriptor implementation.
                /// 
                EventDescriptorCollection ICustomTypeDescriptor.GetEvents() 
                {
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider. 
                    // If so, we can call on it directly rather than creating another 
                    // custom type descriptor
 
                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
                    EventDescriptorCollection events;
 
                    if (rp != null) {
                        events = rp.GetEvents(_objectType); 
                    } 
                    else {
                        ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance); 
                        if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
                        events = desc.GetEvents();
                        if (events == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetEvents"));
                    } 

                    return events; 
                } 

                ///  
                ///     ICustomTypeDescriptor implementation.
                /// 
                EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
                { 
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another 
                    // custom type descriptor 

                    TypeDescriptionProvider p = _node.Provider; 
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
                    EventDescriptorCollection events;

                    if (rp != null) { 
                        events = rp.GetEvents(_objectType);
                    } 
                    else { 
                        ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
                        if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor")); 
                        events = desc.GetEvents(attributes);
                        if (events == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetEvents"));
                    }
 
                    return events;
                } 
 
                /// 
                ///     ICustomTypeDescriptor implementation. 
                /// 
                PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
                {
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider. 
                    // If so, we can call on it directly rather than creating another
                    // custom type descriptor 
 
                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider; 
                    PropertyDescriptorCollection properties;

                    if (rp != null) {
                        properties = rp.GetProperties(_objectType); 
                    }
                    else { 
                        ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance); 
                        if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
                        properties = desc.GetProperties(); 
                        if (properties == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetProperties"));
                    }

                    return properties; 
                }
 
                ///  
                ///     ICustomTypeDescriptor implementation.
                ///  
                PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
                {
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another 
                    // custom type descriptor
 
                    TypeDescriptionProvider p = _node.Provider; 
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
                    PropertyDescriptorCollection properties; 

                    if (rp != null) {
                        properties = rp.GetProperties(_objectType);
                    } 
                    else {
                        ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance); 
                        if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor")); 
                        properties = desc.GetProperties(attributes);
                        if (properties == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetProperties")); 
                    }

                    return properties;
                } 

                ///  
                ///     ICustomTypeDescriptor implementation. 
                /// 
                object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd) 
                {
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another
                    // custom type descriptor 

                    TypeDescriptionProvider p = _node.Provider; 
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider; 
                    object owner;
 
                    if (rp != null) {
                        owner = rp.GetPropertyOwner(_objectType, _instance, pd);
                    }
                    else { 
                        ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
                        if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor")); 
                        owner = desc.GetPropertyOwner(pd); 
                        if (owner == null) owner = _instance;
                    } 

                    return owner;
                }
            } 
        }
 
        ///  
        ///     This is a simple internal type that allows external parties
        ///     to public ina custom type description provider for COM 
        ///     objects.
        /// 
        [TypeDescriptionProvider("System.Windows.Forms.ComponentModel.Com2Interop.ComNativeDescriptor, " + AssemblyRef.SystemWindowsForms)]
        private sealed class TypeDescriptorComObject 
        {
        } 
    } 
}
 

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

/* 
 */ 
namespace System.ComponentModel
{ 
    using System.Runtime.Serialization.Formatters;
    using System.Threading;
    using System.Runtime.Remoting.Activation;
    using System.Runtime.InteropServices; 
    using System.Diagnostics;
    using System; 
    using CodeAccessPermission = System.Security.CodeAccessPermission; 
    using System.Security.Permissions;
    using System.Collections; 
    using System.Globalization;
    using System.IO;
    using System.Reflection;
    using Microsoft.Win32; 
    using System.ComponentModel.Design;
    using System.Diagnostics.CodeAnalysis; 
    using System.Runtime.Versioning; 

    ///  
    ///    Provides information about the properties and events
    ///    for a component. This class cannot be inherited.
    /// 
    [HostProtection(SharedState = true)] 
    public sealed class TypeDescriptor
    { 
        // Note: this is initialized at class load because we 
        // lock on it for thread safety.  It is used from nearly
        // every call to this class, so it will be created soon after 
        // class load anyway.
        private static WeakHashtable _providerTable     = new WeakHashtable();  // mapping of type or object hash to a provider list
        private static Hashtable     _providerTypeTable = new Hashtable();      // A direct mapping from type to provider.
        private static Hashtable     _defaultProviders  = new Hashtable();      // A table of type -> default provider to track DefaultTypeDescriptionProviderAttributes. 
        private static WeakHashtable _associationTable;
        private static int           _metadataVersion;                          // a version stamp for our metadata.  Used by property descriptors to know when to rebuild 
                                                                                // attributes. 

 
        // This is an index that we use to create a unique name for a property in the
        // event of a name collision.  The only time we should use this is when
        // a name collision happened on an extender property that has no site or
        // no name on its site.  Should be very rare. 
        private static int _collisionIndex;
 
        // events 
        private static RefreshEventHandler _refreshHandler;
 
        private static BooleanSwitch TraceDescriptor = new BooleanSwitch("TypeDescriptor", "Debug TypeDescriptor.");

        #if DEBUG
        private static BooleanSwitch EnableValidation = new BooleanSwitch("EnableValidation", "Enable type descriptor Whidbey->RTM validation"); 
        #endif
 
        // For each stage of our filtering pipeline, the pipeline needs to know 
        // what it is filtering.
        private const int PIPELINE_ATTRIBUTES = 0x00; 
        private const int PIPELINE_PROPERTIES = 0x01;
        private const int PIPELINE_EVENTS = 0x02;

        // And each stage of the pipeline needs to have its own 
        // keys for its cache table.  We use guids because they
        // are unique and fast to compare.  The order for each of 
        // these keys must match the Id's of the filter type above. 
        private static readonly Guid[] _pipelineInitializeKeys = new Guid[]
        { 
            Guid.NewGuid(), // attributes
            Guid.NewGuid(), // properties
            Guid.NewGuid()  // events
        }; 

        private static readonly Guid[] _pipelineMergeKeys = new Guid[] 
        { 
            Guid.NewGuid(), // attributes
            Guid.NewGuid(), // properties 
            Guid.NewGuid()  // events
        };

        private static readonly Guid[] _pipelineFilterKeys = new Guid[] 
        {
            Guid.NewGuid(), // attributes 
            Guid.NewGuid(), // properties 
            Guid.NewGuid()  // events
        }; 

        private static readonly Guid[] _pipelineAttributeFilterKeys = new Guid[]
        {
            Guid.NewGuid(), // attributes 
            Guid.NewGuid(), // properties
            Guid.NewGuid()  // events 
        }; 

        private static object _internalSyncObject = new object(); 

        private TypeDescriptor()
        {
        } 

        ///  
        ///  
        /// 
        [Obsolete("This property has been deprecated.  Use a type description provider to supply type information for COM types instead.  http://go.microsoft.com/fwlink/?linkid=14202")] 
        public static IComNativeDescriptorHandler ComNativeDescriptorHandler
        {
            [PermissionSetAttribute(SecurityAction.LinkDemand, Name="FullTrust")]
            get 
            {
                TypeDescriptionNode node = NodeFor(ComObjectType); 
                ComNativeDescriptionProvider provider = null; 

                do 
                {
                    provider = node.Provider as ComNativeDescriptionProvider;
                    node = node.Next;
                } 
                while(node != null && provider == null);
 
                if (provider != null) 
                {
                    return provider.Handler; 
                }

                return null;
            } 
            [PermissionSetAttribute(SecurityAction.LinkDemand, Name="FullTrust")]
            set 
            { 
                TypeDescriptionNode node = NodeFor(ComObjectType);
 
                while (node != null && !(node.Provider is ComNativeDescriptionProvider))
                {
                    node = node.Next;
                } 

                if (node == null) 
                { 
                    AddProvider(new ComNativeDescriptionProvider(value), ComObjectType);
                } 
                else
                {
                    ComNativeDescriptionProvider provider = (ComNativeDescriptionProvider)node.Provider;
                    provider.Handler = value; 
                }
            } 
        } 

 
        /// 
        ///     This property returns a Type object that can be passed to the various
        ///     AddProvider methods to define a type description provider for COM types.
        ///  
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static Type ComObjectType 
        { 
            get
            { 
                return typeof(TypeDescriptorComObject);
            }
        }
 
        /// 
        ///     This value increments each time someone refreshes or changes metadata. 
        ///  
        internal static int MetadataVersion {
            get { 
                return _metadataVersion;
            }
        }
 
        /// 
        ///  
        ///    Occurs when Refreshed is raised for a component. 
        /// 
        public static event RefreshEventHandler Refreshed 
        {
            add
            {
                _refreshHandler += value; 
            }
            remove 
            { 
                _refreshHandler -= value;
            } 
        }

        /// 
        ///     The AddAttributes method allows you to add class-level attributes for a 
        ///     type or an instance.  This method simply implements a type description provider
        ///     that merges the provided attributes with the attributes that already exist on 
        ///     the class.  This is a short cut for such a behavior.  Adding additional 
        ///     attributes is common need for applications using the Windows Forms property
        ///     window.  The return value form AddAttributes is the TypeDescriptionProvider 
        ///     that was used to add the attributes.  This provider can later be passed to
        ///     RemoveProvider if the added attributes are no longer needed.
        /// 
        [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")] 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static TypeDescriptionProvider AddAttributes(Type type, params Attribute[] attributes) { 
 
            if (type == null) {
                throw new ArgumentNullException("type"); 
            }

            if (attributes == null) {
                throw new ArgumentNullException("attributes"); 
            }
 
            TypeDescriptionProvider existingProvider = GetProvider(type); 
            TypeDescriptionProvider provider = new AttributeProvider(existingProvider, attributes);
            TypeDescriptor.AddProvider(provider, type); 
            return provider;
        }

        ///  
        ///     The AddAttributes method allows you to add class-level attributes for a
        ///     type or an instance.  This method simply implements a type description provider 
        ///     that merges the provided attributes with the attributes that already exist on 
        ///     the class.  This is a short cut for such a behavior.  Adding additional
        ///     attributes is common need for applications using the Windows Forms property 
        ///     window.  The return value form AddAttributes is the TypeDescriptionProvider
        ///     that was used to add the attributes.  This provider can later be passed to
        ///     RemoveProvider if the added attributes are no longer needed.
        ///  
        [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        public static TypeDescriptionProvider AddAttributes(object instance, params Attribute[] attributes) { 

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

            if (attributes == null) { 
                throw new ArgumentNullException("attributes");
            } 
 
            TypeDescriptionProvider existingProvider = GetProvider(instance);
            TypeDescriptionProvider provider = new AttributeProvider(existingProvider, attributes); 
            TypeDescriptor.AddProvider(provider, instance);
            return provider;
        }
 
        /// 
        ///  
        ///     Adds an editor table for the given editor base type. 
        ///     ypically, editors are specified as metadata on an object. If no metadata for a
        ///     equested editor base type can be found on an object, however, the 
        ///     ypeDescriptor will search an editor
        ///     able for the editor type, if one can be found.
        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        public static void AddEditorTable(Type editorBaseType, Hashtable table)
        { 
            ReflectTypeDescriptionProvider.AddEditorTable(editorBaseType, table); 
        }
 
        /// 
        ///     Adds a type description provider that will be called on to provide
        ///     type and instance information for any object that is of, or a subtype
        ///     of, the provided type.  Type can be any type, including interfaces. 
        ///     For example, to provide custom type and instance information for all
        ///     components, you would pass typeof(IComponent).  Passing typeof(object) 
        ///     will cause the provider to be called to provide type information for 
        ///     all types.
        ///  
        [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static void AddProvider(TypeDescriptionProvider provider, Type type)
        { 
            if (provider == null)
            { 
                throw new ArgumentNullException("provider"); 
            }
 
            if (type == null)
            {
                throw new ArgumentNullException("type");
            } 

            lock(_providerTable) 
            { 
                // Get the root node, hook it up, and stuff it back into
                // the provider cache. 
                TypeDescriptionNode node = NodeFor(type, true);
                TypeDescriptionNode head = new TypeDescriptionNode(provider);
                head.Next = node;
                _providerTable[type] = head; 
                _providerTypeTable.Clear();
            } 
 
            Refresh(type);
        } 

        /// 
        ///     Adds a type description provider that will be called on to provide
        ///     type information for a single object instance.  A provider added 
        ///     using this method will never have its CreateInstance method called
        ///     because the instance already exists.  This method does not prevent 
        ///     the object from finalizing. 
        /// 
        [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")] 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static void AddProvider(TypeDescriptionProvider provider, object instance)
        {
            if (provider == null) 
            {
                throw new ArgumentNullException("provider"); 
            } 

            if (instance == null) 
            {
                throw new ArgumentNullException("instance");
            }
 
            // Get the root node, hook it up, and stuff it back into
            // the provider cache. 
            lock(_providerTable) 
            {
                TypeDescriptionNode node = NodeFor(instance, true); 
                TypeDescriptionNode head = new TypeDescriptionNode(provider);
                head.Next = node;
                _providerTable.SetWeak(instance, head);
                _providerTypeTable.Clear(); 
            }
 
            Refresh(instance); 
        }
 
        /// 
        ///     This method verifies that we have checked for the presence
        ///     of a default type description provider attribute for the
        ///     given type. 
        /// 
        //See security note below 
        [SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts")] 
        private static void CheckDefaultProvider(Type type)
        { 
            if (_defaultProviders == null)
            {
                lock (_internalSyncObject)
                { 
                    if (_defaultProviders == null)
                    { 
                        _defaultProviders = new Hashtable(); 
                    }
                } 
            }

            if (_defaultProviders.ContainsKey(type))
            { 
                return;
            } 
 
            lock (_internalSyncObject)
            { 
                if (_defaultProviders.ContainsKey(type))
                {
                    return;
                } 

                // Immediately clear this.  If we find a default provider 
                // and it starts messing around with type information, 
                // this could infinitely recurse.
                // 
                _defaultProviders[type] = null;
            }

            // Always use core reflection when checking for 
            // the default provider attribute.  If there is a
            // provider, we probably don't want to build up our 
            // own cache state against the type.  There shouldn't be 
            // more than one of these, but walk anyway.  Walk in
            // reverse order so that the most derived takes precidence. 
            //
            object[] attrs = type.GetCustomAttributes(typeof(TypeDescriptionProviderAttribute), false);
            bool providerAdded = false;
            for (int idx = attrs.Length - 1; idx >= 0; idx--) 
            {
                TypeDescriptionProviderAttribute pa = (TypeDescriptionProviderAttribute)attrs[idx]; 
                Type providerType = Type.GetType(pa.TypeName); 
                if (providerType != null && typeof(TypeDescriptionProvider).IsAssignableFrom(providerType))
                { 
                    TypeDescriptionProvider prov;

                    // Security Note: TypeDescriptionProviders are similar to TypeConverters and UITypeEditors in the
                    // sense that they provide a public API while not necessarily being public themselves. As such, 
                    // we need to allow instantiation of internal TypeDescriptionProviders. See the thread attached
                    // to VSWhidbey #500522 for a more detailed discussion. 
                    IntSecurity.FullReflection.Assert(); 
                    try {
                        prov = (TypeDescriptionProvider)Activator.CreateInstance(providerType); 
                    }
                    finally {
                        CodeAccessPermission.RevertAssert();
                    } 
                    Trace("Providers : Default provider found : {0}", providerType.Name);
                    AddProvider(prov, type); 
                    providerAdded = true; 
                }
            } 

            // If we did not add a provider, check the base class.
            if (!providerAdded) {
                Type baseType = type.BaseType; 
                if (baseType != null && baseType != type) {
                    CheckDefaultProvider(baseType); 
                } 
            }
        } 

        /// 
        ///     The CreateAssocation method creates an association between two objects.
        ///     Once an association is created, a designer or other filtering mechanism 
        ///     can add properties that route to either object into the primary object's
        ///     property set.  When a property invocation is made against the primary 
        ///     object, GetAssocation will be called to resolve the actual object 
        ///     instance that is related to its type parameter.
        ///  
        [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static void CreateAssociation(object primary, object secondary)
        { 
            if (primary == null)
            { 
                throw new ArgumentNullException("primary"); 
            }
 
            if (secondary == null)
            {
                throw new ArgumentNullException("secondary");
            } 

            if (primary == secondary) 
            { 
                throw new ArgumentException(SR.GetString(SR.TypeDescriptorSameAssociation));
            } 

            if (_associationTable == null)
            {
                lock (_internalSyncObject) 
                {
                    if (_associationTable == null) 
                    { 
                        _associationTable = new WeakHashtable();
                    } 
                }
            }

            IList associations = (IList)_associationTable[primary]; 

            if (associations == null) 
            { 
                lock (_associationTable)
                { 
                    associations = (IList)_associationTable[primary];
                    if (associations == null)
                    {
                        associations = new ArrayList(4); 
                        _associationTable.SetWeak(primary, associations);
                    } 
                } 
            }
            else 
            {
                for (int idx = associations.Count - 1; idx >= 0; idx--)
                {
                    WeakReference r = (WeakReference)associations[idx]; 
                    if (r.IsAlive && r.Target == secondary)
                    { 
                        throw new ArgumentException(SR.GetString(SR.TypeDescriptorAlreadyAssociated)); 
                    }
                } 
            }

            lock(associations)
            { 
                associations.Add(new WeakReference(secondary));
            } 
        } 

        ///  
        ///     Creates an instance of the designer associated with the
        ///     specified component.
        /// 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2113:SecureLateBindingMethods")] 
        public static IDesigner CreateDesigner(IComponent component, Type designerBaseType)
        { 
            Type designerType = null; 
            IDesigner designer = null;
 
            // Get the set of attributes for this type
            //
            AttributeCollection attributes = GetAttributes(component);
 
            for (int i = 0; i < attributes.Count; i++)
            { 
                DesignerAttribute da = attributes[i] as DesignerAttribute; 
                if (da != null)
                { 
                    Type attributeBaseType = Type.GetType(da.DesignerBaseTypeName);
                    if (attributeBaseType != null && attributeBaseType == designerBaseType)
                    {
                        ISite site = component.Site; 
                        bool foundService = false;
 
                        if (site != null) 
                        {
                            ITypeResolutionService tr = (ITypeResolutionService)site.GetService(typeof(ITypeResolutionService)); 
                            if (tr != null)
                            {
                                foundService = true;
                                designerType = tr.GetType(da.DesignerTypeName); 
                            }
                        } 
 
                        if (!foundService)
                        { 
                            designerType = Type.GetType(da.DesignerTypeName);
                        }

                        Debug.Assert(designerType != null, "It may be okay for the designer not to load, but we failed to load designer for component of type '" + component.GetType().FullName + "' because designer of type '" + da.DesignerTypeName + "'"); 
                        if (designerType != null)
                        { 
                            break; 
                        }
                    } 
                }
            }

            if (designerType != null) 
            {
                designer = (IDesigner)SecurityUtils.SecureCreateInstance(designerType, null, true); 
            } 

            return designer; 
        }

        /// 
        ///     This dynamically binds an EventDescriptor to a type. 
        /// 
        [ReflectionPermission(SecurityAction.LinkDemand, Flags=ReflectionPermissionFlag.MemberAccess)] 
        public static EventDescriptor CreateEvent(Type componentType, string name, Type type, params Attribute[] attributes) 
        {
            return new ReflectEventDescriptor(componentType, name, type, attributes); 
        }

        /// 
        ///     This creates a new event descriptor identical to an existing event descriptor.  The new event descriptor 
        ///     has the specified metadata attributes merged with the existing metadata attributes.
        ///  
        [ReflectionPermission(SecurityAction.LinkDemand, Flags=ReflectionPermissionFlag.MemberAccess)] 
        public static EventDescriptor CreateEvent(Type componentType, EventDescriptor oldEventDescriptor, params Attribute[] attributes)
        { 
            return new ReflectEventDescriptor(componentType, oldEventDescriptor, attributes);
        }

        ///  
        ///     This method will search internal tables within TypeDescriptor for
        ///     a TypeDescriptionProvider object that is associated with the given 
        ///     data type.  If it finds one, it will delegate the call to that object. 
        /// 
        public static object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args) 
        {
            if (objectType == null)
            {
                throw new ArgumentNullException("objectType"); 
            }
 
            if (argTypes != null) 
            {
                if (args == null) 
                {
                    throw new ArgumentNullException("args");
                }
 
                if (argTypes.Length != args.Length)
                { 
                    throw new ArgumentException(SR.GetString(SR.TypeDescriptorArgsCountMismatch)); 
                }
            } 

            object instance = null;

            // See if the provider wants to offer a TypeDescriptionProvider to delegate to.  This allows 
            // a caller to have complete control over all object instantiation.
            if (provider != null) { 
                TypeDescriptionProvider p = provider.GetService(typeof(TypeDescriptionProvider)) as TypeDescriptionProvider; 
                if (p != null) {
                    instance = p.CreateInstance(provider, objectType, argTypes, args); 
                }
            }

            if (instance == null) { 
                instance = NodeFor(objectType).CreateInstance(provider, objectType, argTypes, args);
            } 
 
            return instance;
        } 

        /// 
        ///     This dynamically binds a PropertyDescriptor to a type.
        ///  
        [ReflectionPermission(SecurityAction.LinkDemand, Flags=ReflectionPermissionFlag.MemberAccess)]
        public static PropertyDescriptor CreateProperty(Type componentType, string name, Type type, params Attribute[] attributes) 
        { 
            return new ReflectPropertyDescriptor(componentType, name, type, attributes);
        } 

        /// 
        ///     This creates a new property descriptor identical to an existing property descriptor.  The new property descriptor
        ///     has the specified metadata attributes merged with the existing metadata attributes. 
        /// 
        [ReflectionPermission(SecurityAction.LinkDemand, Flags=ReflectionPermissionFlag.MemberAccess)] 
        public static PropertyDescriptor CreateProperty(Type componentType, PropertyDescriptor oldPropertyDescriptor, params Attribute[] attributes) 
        {
 
            // We must do some special case work here for extended properties.  If the old property descriptor is really
            // an extender property that is being surfaced on a component as a normal property, then we must
            // do work here or else ReflectPropertyDescriptor will fail to resolve the get and set methods.  We check
            // for the necessary ExtenderProvidedPropertyAttribute and if we find it, we create an 
            // ExtendedPropertyDescriptor instead.  We only do this if the component class is the same, since the user
            // may want to re-route the property to a different target. 
            // 
            if (componentType == oldPropertyDescriptor.ComponentType)
            { 
                ExtenderProvidedPropertyAttribute attr = (ExtenderProvidedPropertyAttribute)
                                                         oldPropertyDescriptor.Attributes[
                                                         typeof(ExtenderProvidedPropertyAttribute)];
 
                ReflectPropertyDescriptor reflectDesc = attr.ExtenderProperty as ReflectPropertyDescriptor;
                if (reflectDesc != null) 
                { 
                    return new ExtendedPropertyDescriptor(oldPropertyDescriptor, attributes);
                } 
                #if DEBUG
                else
                {
                    DebugReflectPropertyDescriptor debugReflectDesc = attr.ExtenderProperty as DebugReflectPropertyDescriptor; 
                    if (debugReflectDesc != null)
                    { 
                        return new DebugExtendedPropertyDescriptor(oldPropertyDescriptor, attributes); 
                    }
                } 
                #endif
            }

            // This is either a normal prop or the caller has changed target classes. 
            //
            return new ReflectPropertyDescriptor(componentType, oldPropertyDescriptor, attributes); 
        } 

        ///  
        ///     Debug code that runs the output of a TypeDescriptor query into a debug
        ///     type descriptor that uses the V1.0 algorithm.  This code will assert
        ///     if the two type descriptors do not agree.  This method returns true if
        ///     validation should be performed for the type. 
        /// 
        #if DEBUG 
        private static bool DebugShouldValidate(object key) 
        {
            // Check our switch first. 
            //
            if (EnableValidation.Enabled)
            {
                while(key != null) 
                {
                    // We only validate if there are no custom providers all the way 
                    // up the class chain. 
                    TypeDescriptionNode node = _providerTable[key] as TypeDescriptionNode;
                    if (node != null && !(node.Provider is ReflectTypeDescriptionProvider)) 
                    {
                        return false;
                    }
 
                    if (key is Type)
                    { 
                        key = ((Type)key).BaseType; 
                    }
                    else 
                    {
                        key = key.GetType();
                        if (((Type)key).IsCOMObject)
                        { 
                            key = ComObjectType;
                        } 
                    } 
                }
                return true; 
            }
            return false;
        }
        #endif 

        ///  
        ///     Debug code that runs the output of a TypeDescriptor query into a debug 
        ///     type descriptor that uses the V1.0 algorithm.  This code will assert
        ///     if the two type descriptors do not agree. 
        /// 
        [Conditional("DEBUG")]
        private static void DebugValidate(Type type, AttributeCollection attributes, AttributeCollection debugAttributes)
        { 
            #if DEBUG
            if (!DebugShouldValidate(type)) return; 
            DebugValidate(attributes, debugAttributes); 
            #endif
        } 

        /// 
        ///     Debug code that runs the output of a TypeDescriptor query into a debug
        ///     type descriptor that uses the V1.0 algorithm.  This code will assert 
        ///     if the two type descriptors do not agree.
        ///  
        [Conditional("DEBUG")] 
        private static void DebugValidate(AttributeCollection attributes, AttributeCollection debugAttributes)
        { 
            #if DEBUG

            if (attributes.Count >= debugAttributes.Count)
            { 
                foreach(Attribute a in attributes)
                { 
                    if (!(a is GuidAttribute) && !(a is ComVisibleAttribute)) 
                    {
                        bool found = false; 
                        bool typeFound = false;

                        // Many attributes don't implement .Equals correctly,
                        // so they will fail an equality check.  But we want to 
                        // make sure that common ones like Browsable and ReadOnly
                        // were correctly picked up.  So only check the ones in 
                        // component model. 
                        if (!a.GetType().FullName.StartsWith("System.Component"))
                        { 
                            found = true;
                            break;
                        }
 
                        if (!found)
                        { 
                            foreach(Attribute b in debugAttributes) 
                            {
                                if (!typeFound && a.GetType() == b.GetType()) 
                                {
                                    typeFound = true;
                                }
 
                                // Semitrust may throw here.
                                try 
                                { 
                                    if (a.Equals(b))
                                    { 
                                        found = true;
                                        break;
                                    }
                                } 
                                catch
                                { 
                                    found = true; 
                                    break;
                                } 
                            }
                        }

                        if (!found && !a.IsDefaultAttribute()) 
                        {
                            if (typeFound) 
                            { 
                                Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Attribute {0} was found but failed equality.  Perhaps attribute .Equals is not implemented correctly?", a.GetType().Name));
                            } 
                            else
                            {
                                Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Attribute {0} should not exist", a.GetType().Name));
                            } 
                        }
                    } 
                } 
            }
            else 
            {
                foreach(Attribute b in debugAttributes)
                {
                    // We skip all interop attributes because interface merging has changed on purpose. 
                    if (!(b is GuidAttribute) && !(b is ComVisibleAttribute) && !(b is InterfaceTypeAttribute) && !(b is ReadOnlyAttribute))
                    { 
                        bool found = false; 
                        bool typeFound = false;
 
                        // Many attributes don't implement .Equals correctly,
                        // so they will fail an equality check.  But we want to
                        // make sure that common ones like Browsable and ReadOnly
                        // were correctly picked up.  So only check the ones in 
                        // component model.
                        if (!b.GetType().FullName.StartsWith("System.Component")) 
                        { 
                            found = true;
                            break; 
                        }

                        if (!found)
                        { 
                            foreach(Attribute a in attributes)
                            { 
                                if (!typeFound && a.GetType() == b.GetType()) 
                                {
                                    typeFound = true; 
                                }

                                // Semitrust may throw here.
                                try 
                                {
                                    if (b.Equals(a)) 
                                    { 
                                        found = true;
                                        break; 
                                    }
                                }
                                catch
                                { 
                                    found = true;
                                    break; 
                                } 
                            }
                        } 

                        if (!found && !b.IsDefaultAttribute())
                        {
                            if (!typeFound) 
                            {
                                Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Attribute {0} should exist", b.GetType().Name)); 
                            } 
                        }
                    } 
                }
            }
#endif
        } 

        ///  
        ///     Debug code that runs the output of a TypeDescriptor query into a debug 
        ///     type descriptor that uses the V1.0 algorithm.  This code will assert
        ///     if the two type descriptors do not agree. 
        /// 
        [Conditional("DEBUG")]
        private static void DebugValidate(AttributeCollection attributes, Type type)
        { 
            #if DEBUG
            if (!DebugShouldValidate(type)) return; 
            AttributeCollection debugAttributes = DebugTypeDescriptor.GetAttributes(type); 
            DebugValidate(attributes, debugAttributes);
            #endif 
        }

        /// 
        ///     Debug code that runs the output of a TypeDescriptor query into a debug 
        ///     type descriptor that uses the V1.0 algorithm.  This code will assert
        ///     if the two type descriptors do not agree. 
        ///  
        [Conditional("DEBUG")]
        private static void DebugValidate(AttributeCollection attributes, object instance, bool noCustomTypeDesc) 
        {
            #if DEBUG
            if (!DebugShouldValidate(instance)) return;
            AttributeCollection debugAttributes = DebugTypeDescriptor.GetAttributes(instance, noCustomTypeDesc); 
            DebugValidate(attributes, debugAttributes);
            #endif 
        } 

        ///  
        ///     Debug code that runs the output of a TypeDescriptor query into a debug
        ///     type descriptor that uses the V1.0 algorithm.  This code will assert
        ///     if the two type descriptors do not agree.
        ///  
        [Conditional("DEBUG")]
        private static void DebugValidate(TypeConverter converter, Type type) 
        { 
            #if DEBUG
            if (!DebugShouldValidate(type)) return; 
            TypeConverter debugConverter = DebugTypeDescriptor.GetConverter(type);
            Debug.Assert(debugConverter.GetType() == converter.GetType(), "TypeDescriptor engine Validation Failure.");
            #endif
        } 

        ///  
        ///     Debug code that runs the output of a TypeDescriptor query into a debug 
        ///     type descriptor that uses the V1.0 algorithm.  This code will assert
        ///     if the two type descriptors do not agree. 
        /// 
        [Conditional("DEBUG")]
        private static void DebugValidate(TypeConverter converter, object instance, bool noCustomTypeDesc)
        { 
            #if DEBUG
            if (!DebugShouldValidate(instance)) return; 
            TypeConverter debugConverter = DebugTypeDescriptor.GetConverter(instance, noCustomTypeDesc); 
            Debug.Assert(debugConverter.GetType() == converter.GetType(), "TypeDescriptor engine Validation Failure.");
            #endif 
        }

        /// 
        ///     Debug code that runs the output of a TypeDescriptor query into a debug 
        ///     type descriptor that uses the V1.0 algorithm.  This code will assert
        ///     if the two type descriptors do not agree. 
        ///  
        [Conditional("DEBUG")]
        private static void DebugValidate(EventDescriptorCollection events, Type type, Attribute[] attributes) 
        {
            #if DEBUG
            if (!DebugShouldValidate(type)) return;
            EventDescriptorCollection debugEvents = DebugTypeDescriptor.GetEvents(type, attributes); 
            Debug.Assert(debugEvents.Count == events.Count, "TypeDescriptor engine Validation Failure. Event counts differ.");
            foreach(EventDescriptor debugEvt in debugEvents) 
            { 
                EventDescriptor evt = null;
 
                foreach(EventDescriptor realEvt in events)
                {
                    if (realEvt.Name.Equals(debugEvt.Name) && realEvt.EventType == debugEvt.EventType && realEvt.ComponentType == debugEvt.ComponentType)
                    { 
                        evt = realEvt;
                        break; 
                    } 
                }
 
                Debug.Assert(evt != null, "TypeDescriptor engine Validation Failure. Event " + debugEvt.Name + " does not exist or is of the wrong type.");
                if (evt != null)
                {
                    AttributeCollection attrs = evt.Attributes; 
                    if (attrs[typeof(AttributeProviderAttribute)] == null)
                    { 
                        AttributeCollection debugAttrs = debugEvt.Attributes; 
                        DebugValidate(evt.EventType, attrs, debugAttrs);
                    } 
                }
            }
            #endif
        } 

        ///  
        ///     Debug code that runs the output of a TypeDescriptor query into a debug 
        ///     type descriptor that uses the V1.0 algorithm.  This code will assert
        ///     if the two type descriptors do not agree. 
        /// 
        [Conditional("DEBUG")]
        private static void DebugValidate(EventDescriptorCollection events, object instance, Attribute[] attributes, bool noCustomTypeDesc)
        { 
            #if DEBUG
            if (!DebugShouldValidate(instance)) return; 
            EventDescriptorCollection debugEvents = DebugTypeDescriptor.GetEvents(instance, attributes, noCustomTypeDesc); 
            Debug.Assert(debugEvents.Count == events.Count, "TypeDescriptor engine Validation Failure. Event counts differ.");
            foreach(EventDescriptor debugEvt in debugEvents) 
            {
                EventDescriptor evt = null;

                foreach(EventDescriptor realEvt in events) 
                {
                    if (realEvt.Name.Equals(debugEvt.Name) && realEvt.EventType == debugEvt.EventType && realEvt.ComponentType == debugEvt.ComponentType) 
                    { 
                        evt = realEvt;
                        break; 
                    }
                }

                Debug.Assert(evt != null, "TypeDescriptor engine Validation Failure. Event " + debugEvt.Name + " does not exist or is of the wrong type."); 
                if (evt != null)
                { 
                    AttributeCollection attrs = evt.Attributes; 
                    if (attrs[typeof(AttributeProviderAttribute)] == null)
                    { 
                        AttributeCollection debugAttrs = debugEvt.Attributes;
                        DebugValidate(evt.EventType, attrs, debugAttrs);
                    }
                } 
            }
            #endif 
        } 

        ///  
        ///     Debug code that runs the output of a TypeDescriptor query into a debug
        ///     type descriptor that uses the V1.0 algorithm.  This code will assert
        ///     if the two type descriptors do not agree.
        ///  
        [Conditional("DEBUG")]
        private static void DebugValidate(PropertyDescriptorCollection properties, Type type, Attribute[] attributes) 
        { 
            #if DEBUG
            if (!DebugShouldValidate(type)) return; 
            PropertyDescriptorCollection debugProperties = DebugTypeDescriptor.GetProperties(type, attributes);

            if (debugProperties.Count > properties.Count)
            { 
                foreach(PropertyDescriptor debugProp in debugProperties)
                { 
                    PropertyDescriptor prop = null; 

                    foreach(PropertyDescriptor realProp in properties) 
                    {
                        if (realProp.Name.Equals(debugProp.Name) && realProp.PropertyType == debugProp.PropertyType && realProp.ComponentType == debugProp.ComponentType)
                        {
                            prop = realProp; 
                            break;
                        } 
                    } 

                    if (prop == null) 
                    {
                        Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} should exist.", debugProp.Name, debugProp.GetType().Name));
                    }
                } 
            }
            else if (properties.Count > debugProperties.Count) 
            { 
                foreach(PropertyDescriptor prop in properties)
                { 
                    PropertyDescriptor debugProp = null;

                    foreach(PropertyDescriptor realProp in debugProperties)
                    { 
                        if (realProp.Name.Equals(prop.Name) && realProp.PropertyType == prop.PropertyType && realProp.ComponentType == prop.ComponentType)
                        { 
                            debugProp = realProp; 
                            break;
                        } 
                    }

                    if (debugProp == null)
                    { 
                        Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} should not exist.", prop.Name, prop.GetType().Name));
                    } 
                } 
            }
            else 
            {
                foreach(PropertyDescriptor debugProp in debugProperties)
                {
                    PropertyDescriptor prop = null; 

                    foreach(PropertyDescriptor realProp in properties) 
                    { 
                        if (realProp.Name.Equals(debugProp.Name) && realProp.PropertyType == debugProp.PropertyType && realProp.ComponentType == debugProp.ComponentType)
                        { 
                            prop = realProp;
                            break;
                        }
                    } 

                    Debug.Assert(prop != null, string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} exists but perhaps type mismatched?", debugProp.Name, debugProp.GetType().Name)); 
                    if (prop != null) 
                    {
                        AttributeCollection attrs = prop.Attributes; 
                        if (attrs[typeof(AttributeProviderAttribute)] == null)
                        {
                            AttributeCollection debugAttrs = debugProp.Attributes;
                            DebugValidate(prop.PropertyType, attrs, debugAttrs); 
                        }
                    } 
                } 
            }
#endif 
        }

        /// 
        ///     Debug code that runs the output of a TypeDescriptor query into a debug 
        ///     type descriptor that uses the V1.0 algorithm.  This code will assert
        ///     if the two type descriptors do not agree. 
        ///  
        [Conditional("DEBUG")]
        private static void DebugValidate(PropertyDescriptorCollection properties, object instance, Attribute[] attributes, bool noCustomTypeDesc) 
        {
            #if DEBUG
            if (!DebugShouldValidate(instance)) return;
            PropertyDescriptorCollection debugProperties = DebugTypeDescriptor.GetProperties(instance, attributes, noCustomTypeDesc); 

            if (debugProperties.Count > properties.Count) 
            { 
                foreach(PropertyDescriptor debugProp in debugProperties)
                { 
                    PropertyDescriptor prop = null;

                    foreach(PropertyDescriptor realProp in properties)
                    { 
                        if (realProp.Name.Equals(debugProp.Name) && realProp.PropertyType == debugProp.PropertyType && realProp.ComponentType == debugProp.ComponentType)
                        { 
                            prop = realProp; 
                            break;
                        } 
                    }

                    if (prop == null)
                    { 
                        Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} should exist.", debugProp.Name, debugProp.GetType().Name));
                    } 
                } 
            }
            else if (properties.Count > debugProperties.Count) 
            {
                foreach(PropertyDescriptor prop in properties)
                {
                    PropertyDescriptor debugProp = null; 

                    foreach(PropertyDescriptor realProp in debugProperties) 
                    { 
                        if (realProp.Name.Equals(prop.Name) && realProp.PropertyType == prop.PropertyType && realProp.ComponentType == prop.ComponentType)
                        { 
                            debugProp = realProp;
                            break;
                        }
                    } 

                    if (debugProp == null) 
                    { 
                        Debug.Fail(string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} should not exist.", prop.Name, prop.GetType().Name));
                    } 
                }
            }
            else
            { 
                foreach(PropertyDescriptor debugProp in debugProperties)
                { 
                    PropertyDescriptor prop = null; 

                    foreach(PropertyDescriptor realProp in properties) 
                    {
                        if (realProp.Name.Equals(debugProp.Name) && realProp.PropertyType == debugProp.PropertyType && realProp.ComponentType == debugProp.ComponentType)
                        {
                            prop = realProp; 
                            break;
                        } 
                    } 

                    Debug.Assert(prop != null, string.Format(CultureInfo.InvariantCulture, "TypeDescriptor engine Validation Failure. Property {0} of type {1} exists but perhaps type mismatched?", debugProp.Name, debugProp.GetType().Name)); 
                    if (prop != null)
                    {
                        AttributeCollection attrs = prop.Attributes;
                        if (attrs[typeof(AttributeProviderAttribute)] == null) 
                        {
                            AttributeCollection debugAttrs = debugProp.Attributes; 
                            DebugValidate(prop.PropertyType, attrs, debugAttrs); 
                        }
                    } 
                }
            }
#endif
        } 

        ///  
        ///     This  API is used to remove any members from the given 
        ///     collection that do not match the attribute array.  If members
        ///     need to be removed, a new ArrayList wil be created that 
        ///     contains only the remaining members. The API returns
        ///     NULL if it did not need to filter any members.
        /// 
        private static ArrayList FilterMembers(IList members, Attribute[] attributes) { 
            ArrayList newMembers = null;
            int memberCount = members.Count; 
 
            for (int idx = 0; idx < memberCount; idx++) {
 
                bool hide = false;

                for (int attrIdx = 0; attrIdx < attributes.Length; attrIdx++) {
                    if (ShouldHideMember((MemberDescriptor)members[idx], attributes[attrIdx])) { 
                        hide = true;
                        break; 
                    } 
                }
 
                if (hide) {
                    // We have to hide.  If this is the first time, we need to init
                    // newMembers to have all the valid members we have previously
                    // hit. 
                    if (newMembers == null) {
                        newMembers = new ArrayList(memberCount); 
                        for (int validIdx = 0; validIdx < idx; validIdx++) { 
                            newMembers.Add(members[validIdx]);
                        } 
                    }
                }
                else if (newMembers != null) {
                        newMembers.Add(members[idx]); 
                }
 
            } 

            return newMembers; 
        }

        /// 
        ///     The GetAssociation method returns the correct object to invoke 
        ///     for the requested type.  It never returns null.
        ///  
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        public static object GetAssociation(Type type, object primary)
        { 
            if (type == null)
            {
                throw new ArgumentNullException("type");
            } 

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

            object associatedObject = primary;

            if (!type.IsInstanceOfType(primary)) 
            {
                // Check our association table for a match. 
                // 
                Hashtable assocTable = _associationTable;
                if (assocTable != null) 
                {
                    IList associations = (IList)assocTable[primary];
                    if (associations != null)
                    { 
                        lock(associations)
                        { 
                            for (int idx = associations.Count - 1; idx >= 0; idx--) 
                            {
                                // Look for an associated object that has a type that 
                                // matches the given type.
                                //
                                WeakReference weakRef = (WeakReference)associations[idx];
                                object secondary = weakRef.Target; 
                                if (secondary == null)
                                { 
                                    Trace("Associations : Removing dead reference in assocation table"); 
                                    associations.RemoveAt(idx);
                                } 
                                else if (type.IsInstanceOfType(secondary))
                                {
                                    Trace("Associations : Associated {0} to {1}", primary.GetType().Name, secondary.GetType().Name);
                                    associatedObject = secondary; 
                                }
                            } 
                        } 
                    }
                } 

                // Not in our table.  We have a default association with a designer
                // if that designer is a component.
                // 
                if (associatedObject == primary)
                { 
                    IComponent component = primary as IComponent; 
                    if (component != null)
                    { 
                        ISite site = component.Site;

                        if (site != null && site.DesignMode)
                        { 
                            IDesignerHost host = site.GetService(typeof(IDesignerHost)) as IDesignerHost;
                            if (host != null) 
                            { 
                                object designer = host.GetDesigner(component);
 
                                // We only use the designer if it has a compatible class.  If we
                                // got here, we're probably hosed because the user just passed in
                                // an object that this PropertyDescriptor can't munch on, but it's
                                // clearer to use that object instance instead of it's designer. 
                                //
                                if (designer != null && type.IsInstanceOfType(designer)) 
                                { 
                                    Trace("Associations : Associated {0} to {1}", primary.GetType().Name, designer.GetType().Name);
                                    associatedObject = designer; 
                                }
                            }
                        }
                    } 
                }
            } 
 
            return associatedObject;
        } 

        /// 
        ///     Gets a collection of attributes for the specified type of component.
        ///  
        public static AttributeCollection GetAttributes(Type componentType)
        { 
            if (componentType == null) 
            {
                Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here"); 
                return new AttributeCollection((Attribute[])null);
            }

            AttributeCollection attributes = GetDescriptor(componentType, "componentType").GetAttributes(); 
            DebugValidate(attributes, componentType);
            return attributes; 
        } 

        ///  
        ///     Gets a collection of attributes for the specified component.
        /// 
        public static AttributeCollection GetAttributes(object component)
        { 
            return GetAttributes(component, false);
        } 
 
        /// 
        ///     Gets a collection of attributes for the specified component. 
        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static AttributeCollection GetAttributes(object component, bool noCustomTypeDesc)
        { 
            if (component == null)
            { 
                Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here"); 
                return new AttributeCollection((Attribute[])null);
            } 

            // We create a sort of pipeline for mucking with metadata.  The pipeline
            // goes through the following process:
            // 
            // 1.  Merge metadata from extenders.
            // 2.  Allow services to filter the metadata 
            // 3.  If an attribute filter was specified, apply that. 
            //
            // The goal here is speed.  We get speed by not copying or 
            // allocating memory.  We do this by allowing each phase of the
            // pipeline to cache its data in the object cache.  If
            // a phase makes a change to the results, this change must cause
            // successive phases to recompute their results as well.  "Results" is 
            // always a collection, and the various stages of the pipeline may
            // replace or modify this collection (depending on if it's a 
            // read-only IList or not).  It is possible for the orignal 
            // descriptor or attribute collection to pass through the entire
            // pipeline without modification. 
            //
            ICustomTypeDescriptor typeDesc = GetDescriptor(component, noCustomTypeDesc);
            ICollection results = typeDesc.GetAttributes();
 
            // If we are handed a custom type descriptor we have several choices of action
            // we can take.  If noCustomTypeDesc is true, it means that the custom type 
            // descriptor is trying to find a baseline set of properties.  In this case 
            // we should merge in extended properties, but we do not let designers filter
            // because we're not done with the property set yet.  If noCustomTypeDesc 
            // is false, we don't do extender properties because the custom type descriptor
            // has already added them.  In this case, we are doing a final pass so we
            // want to apply filtering.  Finally, if the incoming object is not a custom
            // type descriptor, we do extenders and the filter. 
            //
            if (component is ICustomTypeDescriptor) 
            { 
                if (noCustomTypeDesc)
                { 
                    ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component);
                    if (extDesc != null)
                    {
                        ICollection extResults = extDesc.GetAttributes(); 
                        results = PipelineMerge(PIPELINE_ATTRIBUTES, results, extResults, component, null);
                    } 
                } 
                else
                { 
                    results = PipelineFilter(PIPELINE_ATTRIBUTES, results, component, null);
                }
            }
            else 
            {
                IDictionary cache = GetCache(component); 
 
                results = PipelineInitialize(PIPELINE_ATTRIBUTES, results, cache);
 
                ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component);
                if (extDesc != null)
                {
                    ICollection extResults = extDesc.GetAttributes(); 
                    results = PipelineMerge(PIPELINE_ATTRIBUTES, results, extResults, component, cache);
                } 
 
                results = PipelineFilter(PIPELINE_ATTRIBUTES, results, component, cache);
            } 

            AttributeCollection attrs = results as AttributeCollection;
            if (attrs == null)
            { 
                Trace("Attributes : Allocated new attribute collection for {0}", component.GetType().Name);
                Attribute[] attrArray = new Attribute[results.Count]; 
                results.CopyTo(attrArray, 0); 
                attrs = new AttributeCollection(attrArray);
            } 

            DebugValidate(attrs, component, noCustomTypeDesc);
            return attrs;
        } 

        ///  
        ///     Helper function to obtain a cache for the given object. 
        /// 
        internal static IDictionary GetCache(object instance) 
        {
            return NodeFor(instance).GetCache(instance);
        }
 
        /// 
        ///     Gets the name of the class for the specified component. 
        ///  
        public static string GetClassName(object component)
        { 
            return GetClassName(component, false);
        }

        ///  
        ///     Gets the name of the class for the specified component.
        ///  
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        public static string GetClassName(object component, bool noCustomTypeDesc)
        { 
            return GetDescriptor(component, noCustomTypeDesc).GetClassName();
        }

        ///  
        ///     Gets the name of the class for the specified type.
        ///  
        public static string GetClassName(Type componentType) 
        {
            return GetDescriptor(componentType, "componentType").GetClassName(); 
        }

        /// 
        ///       The name of the class for the specified component. 
        /// 
        public static string GetComponentName(object component) 
        { 
            return GetComponentName(component, false);
        } 

        /// 
        ///    Gets the name of the class for the specified component.
        ///  
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static string GetComponentName(object component, bool noCustomTypeDesc) 
        { 
            return GetDescriptor(component, noCustomTypeDesc).GetComponentName();
        } 

        /// 
        ///    Gets a type converter for the type of the specified component.
        ///  
        public static TypeConverter GetConverter(object component)
        { 
            return GetConverter(component, false); 
        }
 
        /// 
        ///    Gets a type converter for the type of the specified component.
        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        public static TypeConverter GetConverter(object component, bool noCustomTypeDesc)
        { 
            TypeConverter converter = GetDescriptor(component, noCustomTypeDesc).GetConverter(); 
            DebugValidate(converter, component, noCustomTypeDesc);
            return converter; 
        }

        /// 
        ///    Gets a type converter for the specified type. 
        /// 
        [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] 
        public static TypeConverter GetConverter(Type type) 
        {
            TypeConverter converter = GetDescriptor(type, "type").GetConverter(); 
            DebugValidate(converter, type);
            return converter;
        }
 
        /// 
        ///     Gets the default event for the specified type of component. 
        ///  
        public static EventDescriptor GetDefaultEvent(Type componentType)
        { 
            if (componentType == null)
            {
                Debug.Fail("COMPAT:  Returning null, but you should not pass null here");
                return null; 
            }
 
            return GetDescriptor(componentType, "componentType").GetDefaultEvent(); 
        }
 
        /// 
        ///     Gets the default event for the specified component.
        /// 
        public static EventDescriptor GetDefaultEvent(object component) 
        {
            return GetDefaultEvent(component, false); 
        } 

        ///  
        ///     Gets the default event for a component.
        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static EventDescriptor GetDefaultEvent(object component, bool noCustomTypeDesc) 
        {
            if (component == null) 
            { 
                Debug.Fail("COMPAT:  Returning null, but you should not pass null here");
                return null; 
            }

            return GetDescriptor(component, noCustomTypeDesc).GetDefaultEvent();
        } 

        ///  
        ///     Gets the default property for the specified type of component. 
        /// 
        public static PropertyDescriptor GetDefaultProperty(Type componentType) 
        {
            if (componentType == null)
            {
                Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here"); 
                return null;
            } 
 
            return GetDescriptor(componentType, "componentType").GetDefaultProperty();
        } 

        /// 
        ///     Gets the default property for the specified component.
        ///  
        public static PropertyDescriptor GetDefaultProperty(object component)
        { 
            return GetDefaultProperty(component, false); 
        }
 
        /// 
        ///     Gets the default property for the specified component.
        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        public static PropertyDescriptor GetDefaultProperty(object component, bool noCustomTypeDesc)
        { 
            if (component == null) 
            {
                Debug.Fail("COMPAT:  Returning null, but you should not pass null here"); 
                return null;
            }

            return GetDescriptor(component, noCustomTypeDesc).GetDefaultProperty(); 
        }
 
        ///  
        ///     Returns a custom type descriptor for the given type.
        ///     Performs arg checking so callers don't have to. 
        /// 
        internal static ICustomTypeDescriptor GetDescriptor(Type type, string typeName)
        {
            if (type == null) 
            {
                throw new ArgumentNullException(typeName); 
            } 

            return NodeFor(type).GetTypeDescriptor(type); 
        }

        /// 
        ///     Returns a custom type descriptor for the given instance. 
        ///     Performs arg checking so callers don't have to.  This
        ///     will call through to instance if it is a custom type 
        ///     descriptor. 
        /// 
        internal static ICustomTypeDescriptor GetDescriptor(object component, bool noCustomTypeDesc) 
        {
            if (component == null)
            {
                throw new ArgumentException("component"); 
            }
 
            if (component is IUnimplemented) { 
                throw new NotSupportedException(SR.GetString(SR.TypeDescriptorUnsupportedRemoteObject, component.GetType().FullName));
            } 


            ICustomTypeDescriptor desc = NodeFor(component).GetTypeDescriptor(component);
            ICustomTypeDescriptor d = component as ICustomTypeDescriptor; 
            if (!noCustomTypeDesc && d != null)
            { 
                desc = new MergedTypeDescriptor(d, desc); 
            }
 
            return desc;
        }

        ///  
        ///     Returns an extended custom type descriptor for the given instance.
        ///  
        internal static ICustomTypeDescriptor GetExtendedDescriptor(object component) 
        {
            if (component == null) 
            {
                throw new ArgumentException("component");
            }
 
            return NodeFor(component).GetExtendedTypeDescriptor(component);
        } 
 
        /// 
        ///     Gets an editor with the specified base type for the 
        ///     specified component.
        /// 
        public static object GetEditor(object component, Type editorBaseType)
        { 
            return GetEditor(component, editorBaseType, false);
        } 
 
        /// 
        ///     Gets an editor with the specified base type for the 
        ///     specified component.
        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static object GetEditor(object component, Type editorBaseType, bool noCustomTypeDesc) 
        {
            if (editorBaseType == null) 
            { 
                throw new ArgumentNullException("editorBaseType");
            } 

            return GetDescriptor(component, noCustomTypeDesc).GetEditor(editorBaseType);
        }
 
        /// 
        ///    Gets an editor with the specified base type for the specified type. 
        ///  
        public static object GetEditor(Type type, Type editorBaseType)
        { 
            if (editorBaseType == null)
            {
                throw new ArgumentNullException("editorBaseType");
            } 

            return GetDescriptor(type, "type").GetEditor(editorBaseType); 
        } 

        ///  
        ///     Gets a collection of events for a specified type of component.
        /// 
        public static EventDescriptorCollection GetEvents(Type componentType)
        { 
            if (componentType == null)
            { 
                Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here"); 
                return new EventDescriptorCollection(null, true);
            } 

            return GetDescriptor(componentType, "componentType").GetEvents();
        }
 
        /// 
        ///     Gets a collection of events for a specified type of 
        ///     component using a specified array of attributes as a filter. 
        /// 
        public static EventDescriptorCollection GetEvents(Type componentType, Attribute[] attributes) 
        {
            if (componentType == null)
            {
                Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here"); 
                return new EventDescriptorCollection(null, true);
            } 
 
            EventDescriptorCollection events = GetDescriptor(componentType, "componentType").GetEvents(attributes);
 
            if (attributes != null && attributes.Length > 0) {
                ArrayList filteredEvents = FilterMembers(events, attributes);
                if (filteredEvents != null) {
                    events = new EventDescriptorCollection((EventDescriptor[])filteredEvents.ToArray(typeof(EventDescriptor)), true); 
                }
            } 
 
            DebugValidate(events, componentType, attributes);
            return events; 
        }

        /// 
        ///     Gets a collection of events for a specified component. 
        /// 
        public static EventDescriptorCollection GetEvents(object component) 
        { 
            return GetEvents(component, null, false);
        } 

        /// 
        ///     Gets a collection of events for a specified component.
        ///  
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static EventDescriptorCollection GetEvents(object component, bool noCustomTypeDesc) 
        { 
            return GetEvents(component, null, noCustomTypeDesc);
        } 

        /// 
        ///     Gets a collection of events for a specified component
        ///     using a specified array of attributes as a filter. 
        /// 
        public static EventDescriptorCollection GetEvents(object component, Attribute[] attributes) 
        { 
            return GetEvents(component, attributes, false);
        } 

        /// 
        ///     Gets a collection of events for a specified component
        ///     using a specified array of attributes as a filter. 
        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        public static EventDescriptorCollection GetEvents(object component, Attribute[] attributes, bool noCustomTypeDesc) 
        {
            if (component == null) 
            {
                Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here");
                return new EventDescriptorCollection(null, true);
            } 

            // We create a sort of pipeline for mucking with metadata.  The pipeline 
            // goes through the following process: 
            //
            // 1.  Merge metadata from extenders. 
            // 2.  Allow services to filter the metadata
            // 3.  If an attribute filter was specified, apply that.
            //
            // The goal here is speed.  We get speed by not copying or 
            // allocating memory.  We do this by allowing each phase of the
            // pipeline to cache its data in the object cache.  If 
            // a phase makes a change to the results, this change must cause 
            // successive phases to recompute their results as well.  "Results" is
            // always a collection, and the various stages of the pipeline may 
            // replace or modify this collection (depending on if it's a
            // read-only IList or not).  It is possible for the orignal
            // descriptor or attribute collection to pass through the entire
            // pipeline without modification. 
            //
            ICustomTypeDescriptor typeDesc = GetDescriptor(component, noCustomTypeDesc); 
            ICollection results; 

            // If we are handed a custom type descriptor we have several choices of action 
            // we can take.  If noCustomTypeDesc is true, it means that the custom type
            // descriptor is trying to find a baseline set of events.  In this case
            // we should merge in extended events, but we do not let designers filter
            // because we're not done with the event set yet.  If noCustomTypeDesc 
            // is false, we don't do extender events because the custom type descriptor
            // has already added them.  In this case, we are doing a final pass so we 
            // want to apply filtering.  Finally, if the incoming object is not a custom 
            // type descriptor, we do extenders and the filter.
            // 
            if (component is ICustomTypeDescriptor)
            {
                results = typeDesc.GetEvents(attributes);
                if (noCustomTypeDesc) 
                {
                    ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component); 
                    if (extDesc != null) 
                    {
                        ICollection extResults = extDesc.GetEvents(attributes); 
                        results = PipelineMerge(PIPELINE_EVENTS, results, extResults, component, null);
                    }
                }
                else 
                {
                    results = PipelineFilter(PIPELINE_EVENTS, results, component, null); 
                    results = PipelineAttributeFilter(PIPELINE_EVENTS, results, attributes, component, null); 
                }
            } 
            else
            {
                IDictionary cache = GetCache(component);
                results = typeDesc.GetEvents(attributes); 
                results = PipelineInitialize(PIPELINE_EVENTS, results, cache);
                ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component); 
                if (extDesc != null) 
                {
                    ICollection extResults = extDesc.GetEvents(attributes); 
                    results = PipelineMerge(PIPELINE_EVENTS, results, extResults, component, cache);
                }

                results = PipelineFilter(PIPELINE_EVENTS, results, component, cache); 
                results = PipelineAttributeFilter(PIPELINE_EVENTS, results, attributes, component, cache);
            } 
 
            EventDescriptorCollection evts = results as EventDescriptorCollection;
            if (evts == null) 
            {
                Trace("Events : Allocated new event collection for {0}", component.GetType().Name);
                EventDescriptor[] eventArray = new EventDescriptor[results.Count];
                results.CopyTo(eventArray, 0); 
                evts = new EventDescriptorCollection(eventArray, true);
            } 
 
            DebugValidate(evts, component, attributes, noCustomTypeDesc);
 
            return evts;
        }

        ///  
        ///     This method is invoked during filtering when a name
        ///     collision is encountered between two properties or events.  This returns 
        ///     a suffix that can be appended to the name to make 
        ///     it unique.  This will first attempt ot use the name of the
        ///     extender.  Failing that it will fall back to a static 
        ///     index that is continually incremented.
        /// 
        private static string GetExtenderCollisionSuffix(MemberDescriptor member)
        { 
            string suffix = null;
 
            ExtenderProvidedPropertyAttribute exAttr = member.Attributes[typeof(ExtenderProvidedPropertyAttribute)] as ExtenderProvidedPropertyAttribute; 
            if (exAttr != null)
            { 
                IExtenderProvider prov = exAttr.Provider;

                if (prov != null)
                { 
                    string name = null;
                    IComponent component = prov as IComponent; 
 
                    if (component != null && component.Site != null)
                    { 
                        name = component.Site.Name;
                    }

                    if (name == null || name.Length == 0) 
                    {
                        name = (_collisionIndex++).ToString(CultureInfo.InvariantCulture); 
                    } 

                    suffix = string.Format(CultureInfo.InvariantCulture, "_{0}", name); 
                }
            }

            return suffix; 
        }
 
        ///  
        ///     The name of the specified component, or null if the component has no name.
        ///     In many cases this will return the same value as GetComponentName. If the 
        ///     component resides in a nested container or has other nested semantics, it may
        ///     return a different fully qualfied name.
        /// 
        public static string GetFullComponentName(object component) { 
            if (component == null) throw new ArgumentNullException("component");
            return GetProvider(component).GetFullComponentName(component); 
        } 

        ///  
        ///     Gets a collection of properties for a specified type of component.
        /// 
        public static PropertyDescriptorCollection GetProperties(Type componentType)
        { 
            if (componentType == null)
            { 
                Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here"); 
                return new PropertyDescriptorCollection(null, true);
            } 

            return GetDescriptor(componentType, "componentType").GetProperties();
        }
 
        /// 
        ///    Gets a collection of properties for a specified type of 
        ///    component using a specified array of attributes as a filter. 
        /// 
        public static PropertyDescriptorCollection GetProperties(Type componentType, Attribute[] attributes) 
        {
            if (componentType == null)
            {
                Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here"); 
                return new PropertyDescriptorCollection(null, true);
            } 
 
            PropertyDescriptorCollection properties = GetDescriptor(componentType, "componentType").GetProperties(attributes);
 
            if (attributes != null && attributes.Length > 0) {
                ArrayList filteredProperties = FilterMembers(properties, attributes);
                if (filteredProperties != null) {
                    properties = new PropertyDescriptorCollection((PropertyDescriptor[])filteredProperties.ToArray(typeof(PropertyDescriptor)), true); 
                }
            } 
 
            DebugValidate(properties, componentType, attributes);
            return properties; 
        }

        /// 
        ///     Gets a collection of properties for a specified component. 
        /// 
        public static PropertyDescriptorCollection GetProperties(object component) 
        { 
            return GetProperties(component, false);
        } 

        /// 
        ///     Gets a collection of properties for a specified component.
        ///  
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static PropertyDescriptorCollection GetProperties(object component, bool noCustomTypeDesc) 
        { 
            return GetPropertiesImpl(component, null, noCustomTypeDesc, true);
        } 

        /// 
        ///    Gets a collection of properties for a specified
        ///    component using a specified array of attributes 
        ///    as a filter.
        ///  
        public static PropertyDescriptorCollection GetProperties(object component, Attribute[] attributes) 
        {
            return GetProperties(component, attributes, false); 
        }

        /// 
        ///    Gets a collection of properties for a specified 
        ///       component using a specified array of attributes
        ///       as a filter. 
        ///  
        public static PropertyDescriptorCollection GetProperties(object component, Attribute[] attributes, bool noCustomTypeDesc) {
            return GetPropertiesImpl(component, attributes, noCustomTypeDesc, false); 
        }

        /// 
        ///    Gets a collection of properties for a specified component. Uses the attribute filter 
        ///    only if noAttributes is false. This is to preserve backward compat for the case when
        ///    no attribute filter was passed in (as against passing in null). 
        ///  
        private static PropertyDescriptorCollection GetPropertiesImpl(object component, Attribute[] attributes, bool noCustomTypeDesc, bool noAttributes) {
            if (component == null) 
            {
                Debug.Fail("COMPAT:  Returning an empty collection, but you should not pass null here");
                return new PropertyDescriptorCollection(null, true);
            } 

            // We create a sort of pipeline for mucking with metadata.  The pipeline 
            // goes through the following process: 
            //
            // 1.  Merge metadata from extenders. 
            // 2.  Allow services to filter the metadata
            // 3.  If an attribute filter was specified, apply that.
            //
            // The goal here is speed.  We get speed by not copying or 
            // allocating memory.  We do this by allowing each phase of the
            // pipeline to cache its data in the object cache.  If 
            // a phase makes a change to the results, this change must cause 
            // successive phases to recompute their results as well.  "Results" is
            // always a collection, and the various stages of the pipeline may 
            // replace or modify this collection (depending on if it's a
            // read-only IList or not).  It is possible for the orignal
            // descriptor or attribute collection to pass through the entire
            // pipeline without modification. 
            //
            ICustomTypeDescriptor typeDesc = GetDescriptor(component, noCustomTypeDesc); 
            ICollection results; 

            // If we are handed a custom type descriptor we have several choices of action 
            // we can take.  If noCustomTypeDesc is true, it means that the custom type
            // descriptor is trying to find a baseline set of properties.  In this case
            // we should merge in extended properties, but we do not let designers filter
            // because we're not done with the property set yet.  If noCustomTypeDesc 
            // is false, we don't do extender properties because the custom type descriptor
            // has already added them.  In this case, we are doing a final pass so we 
            // want to apply filtering.  Finally, if the incoming object is not a custom 
            // type descriptor, we do extenders and the filter.
            // 
            if (component is ICustomTypeDescriptor)
            {
                results = noAttributes ? typeDesc.GetProperties() : typeDesc.GetProperties(attributes);
                if (noCustomTypeDesc) 
                {
                    ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component); 
                    if (extDesc != null) 
                    {
                        ICollection extResults = noAttributes ? extDesc.GetProperties() : extDesc.GetProperties(attributes); 
                        results = PipelineMerge(PIPELINE_PROPERTIES, results, extResults, component, null);
                    }
                }
                else 
                {
                    results = PipelineFilter(PIPELINE_PROPERTIES, results, component, null); 
                    results = PipelineAttributeFilter(PIPELINE_PROPERTIES, results, attributes, component, null); 
                }
            } 
            else
            {
                IDictionary cache = GetCache(component);
                results = noAttributes ? typeDesc.GetProperties() : typeDesc.GetProperties(attributes); 
                results = PipelineInitialize(PIPELINE_PROPERTIES, results, cache);
                ICustomTypeDescriptor extDesc = GetExtendedDescriptor(component); 
                if (extDesc != null) 
                {
                    ICollection extResults = noAttributes ? extDesc.GetProperties() : extDesc.GetProperties(attributes); 
                    results = PipelineMerge(PIPELINE_PROPERTIES, results, extResults, component, cache);
                }

                results = PipelineFilter(PIPELINE_PROPERTIES, results, component, cache); 
                results = PipelineAttributeFilter(PIPELINE_PROPERTIES, results, attributes, component, cache);
            } 
 
            PropertyDescriptorCollection props = results as PropertyDescriptorCollection;
            if (props == null) 
            {
                Trace("Properties : Allocated new property collection for {0}", component.GetType().Name);
                PropertyDescriptor[] propArray = new PropertyDescriptor[results.Count];
                results.CopyTo(propArray, 0); 
                props = new PropertyDescriptorCollection(propArray, true);
            } 
 
            DebugValidate(props, component, attributes, noCustomTypeDesc);
 
            return props;
        }

        ///  
        ///     The GetProvider method returns a type description provider for
        ///     the given object or type.  This will always return a type description 
        ///     provider.  Even the default TypeDescriptor implementation is built on 
        ///     a TypeDescriptionProvider, and this will be returned unless there is
        ///     another provider that someone else has added. 
        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static TypeDescriptionProvider GetProvider(Type type)
        { 
            if (type == null)
            { 
                throw new ArgumentNullException("type"); 
            }
 
            return NodeFor(type, true);
        }

        ///  
        ///     The GetProvider method returns a type description provider for
        ///     the given object or type.  This will always return a type description 
        ///     provider.  Even the default TypeDescriptor implementation is built on 
        ///     a TypeDescriptionProvider, and this will be returned unless there is
        ///     another provider that someone else has added. 
        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static TypeDescriptionProvider GetProvider(object instance)
        { 
            if (instance == null)
            { 
                throw new ArgumentNullException("instance"); 
            }
 
            return NodeFor(instance, true);
        }

        ///  
        ///     This method returns a type description provider, but instead of creating
        ///     a delegating provider for the type, this will walk all base types until 
        ///     it locates a provider.  The provider returned cannot be cached.  This 
        ///     method is used by the DelegatingTypeDescriptionProvider to efficiently
        ///     locate the provider to delegate to. 
        /// 
        internal static TypeDescriptionProvider GetProviderRecursive(Type type) {
            return NodeFor(type, false);
        } 

        ///  
        ///     Returns an Type instance that can be used to perform reflection. 
        /// 
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        public static Type GetReflectionType(Type type)
        {
            if (type == null)
            { 
                throw new ArgumentNullException("type");
            } 
 
            return NodeFor(type).GetReflectionType(type);
        } 

        /// 
        ///     Returns an Type instance that can be used to perform reflection.
        ///  
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static Type GetReflectionType(object instance) 
        { 
            if (instance == null)
            { 
                throw new ArgumentNullException("instance");
            }

            return NodeFor(instance).GetReflectionType(instance); 
        }
 
        ///  
        ///     Retrieves the head type description node for a type.
        ///     A head node pointing to a reflection based type description 
        ///     provider will be created on demand.  This does not create
        ///     a delegator, in which case the node returned may be
        ///     a base type node.
        ///  
        private static TypeDescriptionNode NodeFor(Type type) {
            return NodeFor(type, false); 
        } 

        ///  
        ///     Retrieves the head type description node for a type.
        ///     A head node pointing to a reflection based type description
        ///     provider will be created on demand.
        /// 
        ///     If createDelegator is true, this method will create a delegation
        ///     node for a type if the type has no node of its own.  Delegation 
        ///     nodes should be created if you are going to hand this node 
        ///     out to a user.  Without a delegation node, user code could
        ///     skip providers that are added after their call.  Delegation 
        ///     nodes solve that problem.
        ///
        ///     If createDelegator is false, this method will recurse up the
        ///     base type chain looking for nodes. 
        /// 
        private static TypeDescriptionNode NodeFor(Type type, bool createDelegator) { 
            Debug.Assert(type != null, "Caller should validate"); 
            CheckDefaultProvider(type);
 
            // First, check our provider type table to see if we have a matching
            // provider for this type.  The provider type table is a cache that
            // matches types to providers.  When a new provider is added or
            // an existing one removed, the provider type table is torn 
            // down and automatically rebuilt on demand.
            // 
            TypeDescriptionNode node = null; 
            Type searchType = type;
 
            while (node == null) {

                node = (TypeDescriptionNode)_providerTypeTable[searchType];
                if (node == null) { 
                    node = (TypeDescriptionNode)_providerTable[searchType];
                } 
 
                if (node == null) {
                    Type baseType = searchType.BaseType; 

                    if (searchType == typeof(object) || baseType == null) {
                        lock(_providerTable) {
                            node = (TypeDescriptionNode)_providerTable[searchType]; 

                            if (node == null) { 
                                // The reflect type description provider is a default provider that 
                                // can provide type information for all objects.
                                node = new TypeDescriptionNode(new ReflectTypeDescriptionProvider()); 
                                _providerTable[searchType] = node;
                                Trace("Nodes : Allocated new type node.  Now {0} nodes", _providerTable.Count);
                            }
                        } 
                    }
                    else if (createDelegator) { 
                        node = new TypeDescriptionNode(new DelegatingTypeDescriptionProvider(baseType)); 
                        _providerTypeTable[searchType] = node;
                    } 
                    else {
                        // Continue our search
                        searchType = baseType;
                    } 
                }
            } 
 
            return node;
        } 

        /// 
        ///     Retrieves the head type description node for an instance.
        ///     Instance-based node lists are rare.  If a node list is not 
        ///     available for a given instance, this will return the head node
        ///     for the instance's type. 
        ///  
        private static TypeDescriptionNode NodeFor(object instance)
        { 
            return NodeFor(instance, false);
        }

        ///  
        ///     Retrieves the head type description node for an instance.
        ///     Instance-based node lists are rare.  If a node list is not 
        ///     available for a given instance, this will return the head node 
        ///     for the instance's type.  This variation offers a bool called
        ///     createDelegator.  If true and there is no node list for this 
        ///     instance, NodeFor will create a temporary "delegator node" that,
        ///     when queried, will delegate to the type stored in the instance.
        ///     This is done on demand, which means if someone else added a
        ///     type description provider for the instance's type the delegator 
        ///     would pick up the new type.  If a query is being made that does
        ///     not involve publicly exposing the type description provider for 
        ///     the instance, the query should pass in fase (the default) for 
        ///     createDelegator because no object will be created.
        ///  
        private static TypeDescriptionNode NodeFor(object instance, bool createDelegator)
        {
            // For object instances, the provider cache key is not the object (that
            // would keep it in memory).  Instead, it is a subclass of WeakReference 
            // that overrides GetHashCode and Equals to make it appear to be the
            // object it is wrapping.  A GC'd object causes WeakReference to return 
            // false for all .Equals, but it always returns a valid hash code. 

            Debug.Assert(instance != null, "Caller should validate"); 

            TypeDescriptionNode node = (TypeDescriptionNode)_providerTable[instance];
            if (node == null)
            { 
                Type type = instance.GetType();
 
                if (type.IsCOMObject) 
                {
                    type = ComObjectType; 
                }

                if (createDelegator)
                { 
                    node = new TypeDescriptionNode(new DelegatingTypeDescriptionProvider(type));
                    Trace("Nodes : Allocated new instance node for {0}.  Now {1} nodes", type.Name, _providerTable.Count); 
                } 
                else
                { 
                    node = NodeFor(type);
                }
            }
 
            return node;
        } 
 
        /// 
        ///     Simple linked list code to remove an element 
        ///     from the list.  Returns the new head to the
        ///     list.  If the head points to an instance of
        ///     DelegatingTypeDescriptionProvider, we clear the
        ///     node because all it is doing is delegating elsewhere. 
        ///
        ///     Note that this behaves a little differently from normal 
        ///     linked list code.  In a normal linked list, you remove 
        ///     then target node and fixup the links.  In this linked
        ///     list, we remove the node AFTER the target node, fixup 
        ///     the links, and fixup the underlying providers that each
        ///     node references.  The reason for this is that most
        ///     providers keep a reference to the previous provider,
        ///     which is exposed as one of these nodes.  Therefore, 
        ///     to remove a provider the node following is most likely
        ///     referenced by that provider 
        ///  
        private static void NodeRemove(object key, TypeDescriptionProvider provider)
        { 
            lock(_providerTable)
            {
                TypeDescriptionNode head = (TypeDescriptionNode)_providerTable[key];
                TypeDescriptionNode target = head; 
                TypeDescriptionNode prev = null;
 
                while(target != null && target.Provider != provider) 
                {
                    prev = target; 
                    target = target.Next;
                }

                if (target != null) 
                {
                    // We have our target node.  There are three cases 
                    // to consider:  the target is in the middle, the head, 
                    // or the end.
 
                    if (target.Next != null) {
                        // If there is a node after the target node,
                        // steal the node's provider and store it
                        // at the target location.  This removes 
                        // the provider at the target location without
                        // the need to modify providers which may be 
                        // pointing to "target". 
                        target.Provider = target.Next.Provider;
 
                        // Now remove target.Next from the list
                        target.Next = target.Next.Next;

                        // If the new provider we got is a delegating 
                        // provider, we can remove this node from
                        // the list.  The delegating provider should 
                        // always be at the end of the node list. 
                        if (target == head && target.Provider is DelegatingTypeDescriptionProvider) {
                            Debug.Assert(target.Next == null, "Delegating provider should always be the last provider in the chain."); 
                            _providerTable.Remove(key);
                        }
                    }
                    else if (target != head) { 
                        // If target is the last node, we can't
                        // assign a new provider over to it.  What 
                        // we can do, however, is assign a delegating 
                        // provider into the target node.  This routes
                        // requests from the previous provider into 
                        // the next base type provider list.

                        // We don't do this if the target is the head.
                        // In that case, we can remove the node 
                        // altogether since no one is pointing to it.
 
                        Type keyType = key as Type; 
                        if (keyType == null) keyType = key.GetType();
 
                        target.Provider = new DelegatingTypeDescriptionProvider(keyType.BaseType);
                    }
                    else {
                        _providerTable.Remove(key); 
                    }
 
                    // Finally, clear our cache of provider types; it might be invalid 
                    // now.
                    _providerTypeTable.Clear(); 
                }
            }
        }
 
        /// 
        ///     This is the last stage in our filtering pipeline.  Here, we apply any 
        ///     user-defined filter. 
        /// 
        private static ICollection PipelineAttributeFilter(int pipelineType, ICollection members, Attribute[] filter, object instance, IDictionary cache) 
        {
            Debug.Assert(pipelineType != PIPELINE_ATTRIBUTES, "PipelineAttributeFilter is not supported for attributes");

            IList list = members as ArrayList; 

            if (filter == null || filter.Length == 0) 
            { 
                return members;
            } 

            // Now, check our cache.  The cache state is only valid
            // if the data coming into us is read-only.  If it is read-write,
            // that means something higher in the pipeline has already changed 
            // it so we must recompute anyway.
            // 
            if (cache != null && (list == null || list.IsReadOnly)) 
            {
                AttributeFilterCacheItem filterCache = cache[_pipelineAttributeFilterKeys[pipelineType]] as AttributeFilterCacheItem; 
                if (filterCache != null && filterCache.IsValid(filter))
                {
                    return filterCache.FilteredMembers;
                } 
            }
 
            // Our cache did not contain the correct state, so generate it. 
            //
            if (list == null || list.IsReadOnly) 
            {
                Trace("Pipeline : Filter needs to create member list for {0}", instance.GetType().Name);
                list = new ArrayList(members);
            } 

            ArrayList filterResult = FilterMembers(list, filter); 
            if (filterResult != null) list = filterResult; 

            // And, if we have a cache, store the updated state into it for future reference. 
            //
            if (cache != null)
            {
                ICollection cacheValue; 

                switch(pipelineType) 
                { 
                    case PIPELINE_PROPERTIES:
                        PropertyDescriptor[] propArray = new PropertyDescriptor[list.Count]; 
                        list.CopyTo(propArray, 0);
                        cacheValue = new PropertyDescriptorCollection(propArray, true);
                        break;
 
                    case PIPELINE_EVENTS:
                        EventDescriptor[] eventArray = new EventDescriptor[list.Count]; 
                        list.CopyTo(eventArray, 0); 
                        cacheValue = new EventDescriptorCollection(eventArray, true);
                        break; 

                    default:
                        Debug.Fail("unknown pipeline type");
                        cacheValue = null; 
                        break;
                } 
 
                Trace("Pipeline : Attribute Filter results being cached for {0}", instance.GetType().Name);
                AttributeFilterCacheItem filterCache = new AttributeFilterCacheItem(filter, cacheValue); 
                cache[_pipelineAttributeFilterKeys[pipelineType]] = filterCache;
            }

            return list; 
        }
 
        ///  
        ///     Metdata filtering is the third stage of our pipeline.
        ///     In this stage we check to see if the given object is a 
        ///     sited component that provides the ITypeDescriptorFilterService
        ///     object.  If it does, we allow the TDS to filter the metadata.
        ///     This will use the cache, if available, to store filtered
        ///     metdata. 
        /// 
        private static ICollection PipelineFilter(int pipelineType, ICollection members, object instance, IDictionary cache) 
        { 
            IComponent component = instance as IComponent;
            ITypeDescriptorFilterService componentFilter = null; 

            if (component != null)
            {
                ISite site = component.Site; 
                if (site != null)
                { 
                    componentFilter = site.GetService(typeof(ITypeDescriptorFilterService)) as ITypeDescriptorFilterService; 
                }
            } 

            // If we have no filter, there is nothing for us to do.
            //
            IList list = members as ArrayList; 

            if (componentFilter == null) 
            { 
                Debug.Assert(cache == null || list == null || !cache.Contains(_pipelineFilterKeys[pipelineType]), "Earlier pipeline stage should have removed our cache");
                return members; 
            }

            // Now, check our cache.  The cache state is only valid
            // if the data coming into us is read-only.  If it is read-write, 
            // that means something higher in the pipeline has already changed
            // it so we must recompute anyway. 
            // 
            if (cache != null && (list == null || list.IsReadOnly))
            { 
                FilterCacheItem cacheItem = cache[_pipelineFilterKeys[pipelineType]] as FilterCacheItem;
                if (cacheItem != null && cacheItem.IsValid(componentFilter)) {
                    return cacheItem.FilteredMembers;
                } 
            }
 
            // Cache either is dirty or doesn't exist.  Re-filter the members. 
            // We need to build an IDictionary of key->value pairs and invoke
            // Filter* on the filter service. 
            //
            Hashtable filterTable = new Hashtable(members.Count);
            bool cacheResults;
 
            switch(pipelineType)
            { 
                case PIPELINE_ATTRIBUTES: 
                    foreach(Attribute attr in members)
                    { 
                        filterTable[attr.TypeId] = attr;
                    }
                    cacheResults = componentFilter.FilterAttributes(component, filterTable);
                    break; 

                case PIPELINE_PROPERTIES: 
                case PIPELINE_EVENTS: 
                    foreach(MemberDescriptor desc in members)
                    { 
                        string descName = desc.Name;
                        // We must handle the case of duplicate property names
                        // because extender providers can provide any arbitrary
                        // name.  Our rule for this is simple:  If we find a 
                        // duplicate name, resolve it back to the extender
                        // provider that offered it and append "_" + the 
                        // provider name.  If the provider has no name, 
                        // then append the object hash code.
                        // 
                        if (filterTable.Contains(descName))
                        {
                            // First, handle the new property.  Because
                            // of the order in which we added extended 
                            // properties earlier in the pipeline, we can be
                            // sure that the new property is an extender.  We 
                            // cannot be sure that the existing property 
                            // in the table is an extender, so we will
                            // have to check. 
                            //
                            string suffix = GetExtenderCollisionSuffix(desc);
                            Debug.Assert(suffix != null, "Name collision with non-extender property.");
                            if (suffix != null) 
                            {
                                filterTable[descName + suffix] = desc; 
                            } 

                            // Now, handle the original property. 
                            //
                            MemberDescriptor origDesc = (MemberDescriptor)filterTable[descName];
                            suffix = GetExtenderCollisionSuffix(origDesc);
                            if (suffix != null) 
                            {
                                filterTable.Remove(descName); 
                                filterTable[origDesc.Name + suffix] = origDesc; 
                            }
                        } 
                        else
                        {
                            filterTable[descName] = desc;
                        } 
                    }
                    if (pipelineType == PIPELINE_PROPERTIES) 
                    { 
                        cacheResults = componentFilter.FilterProperties(component, filterTable);
                    } 
                    else
                    {
                        cacheResults = componentFilter.FilterEvents(component, filterTable);
                    } 
                    break;
 
                default: 
                    Debug.Fail("unknown pipeline type");
                    cacheResults = false; 
                    break;
            }

            // See if we can re-use the IList were were passed.  If we can, 
            // it is more efficient to re-use its slots than to generate new ones.
            // 
            if (list == null || list.IsReadOnly) 
            {
                Trace("Pipeline : Filter needs to create member list for {0}", instance.GetType().Name); 
                list = new ArrayList(filterTable.Values);
            }
            else
            { 
                list.Clear();
                foreach(object obj in filterTable.Values) 
                { 
                    list.Add(obj);
                } 
            }

            // Component filter has requested that we cache these
            // new changes.  We store them as a correctly typed collection 
            // so on successive invocations we can simply return.  Note that
            // we always return the IList so that successive stages in the 
            // pipeline can modify it. 
            //
            if (cacheResults && cache != null) 
            {
                ICollection cacheValue;

                switch(pipelineType) 
                {
                    case PIPELINE_ATTRIBUTES: 
                        Attribute[] attrArray = new Attribute[list.Count]; 
                        try
                        { 
                            list.CopyTo(attrArray, 0);
                        }
                        catch(InvalidCastException)
                        { 
                            throw new ArgumentException(SR.GetString(SR.TypeDescriptorExpectedElementType, typeof(Attribute).FullName));
                        } 
                        cacheValue = new AttributeCollection(attrArray); 
                        break;
 
                    case PIPELINE_PROPERTIES:
                        PropertyDescriptor[] propArray = new PropertyDescriptor[list.Count];
                        try
                        { 
                            list.CopyTo(propArray, 0);
                        } 
                        catch(InvalidCastException) 
                        {
                            throw new ArgumentException(SR.GetString(SR.TypeDescriptorExpectedElementType, typeof(PropertyDescriptor).FullName)); 
                        }
                        cacheValue = new PropertyDescriptorCollection(propArray, true);
                        break;
 
                    case PIPELINE_EVENTS:
                        EventDescriptor[] eventArray = new EventDescriptor[list.Count]; 
                        try 
                        {
                            list.CopyTo(eventArray, 0); 
                        }
                        catch(InvalidCastException)
                        {
                            throw new ArgumentException(SR.GetString(SR.TypeDescriptorExpectedElementType, typeof(EventDescriptor).FullName)); 
                        }
                        cacheValue = new EventDescriptorCollection(eventArray, true); 
                        break; 

                    default: 
                        Debug.Fail("unknown pipeline type");
                        cacheValue = null;
                        break;
                } 

                Trace("Pipeline : Filter results being cached for {0}", instance.GetType().Name); 
 
                FilterCacheItem cacheItem = new FilterCacheItem(componentFilter, cacheValue);
                cache[_pipelineFilterKeys[pipelineType]] = cacheItem; 
                cache.Remove(_pipelineAttributeFilterKeys[pipelineType]);
            }

            return list; 
        }
 
        ///  
        /// This is the first stage in the pipeline.  This checks the incoming member collection and if it
        /// differs from what we have seen in the past, it invalidates all successive pipelines. 
        /// 
        private static ICollection PipelineInitialize (int pipelineType, ICollection members, IDictionary cache) {
            if (cache != null) {
 
                bool cacheValid = true;
 
                ICollection cachedMembers = cache[_pipelineInitializeKeys[pipelineType]] as ICollection; 
                if (cachedMembers != null && cachedMembers.Count == members.Count) {
                    IEnumerator cacheEnum = cachedMembers.GetEnumerator(); 
                    IEnumerator memberEnum = members.GetEnumerator();

                    while(cacheEnum.MoveNext() && memberEnum.MoveNext()) {
                        if (cacheEnum.Current != memberEnum.Current) { 
                            cacheValid = false;
                            break; 
                        } 
                    }
                } 

                if (!cacheValid) {
                    // The cache wasn't valid.  Remove all subsequent cache layers
                    // and then save off new data. 
                    cache.Remove(_pipelineMergeKeys[pipelineType]);
                    cache.Remove(_pipelineFilterKeys[pipelineType]); 
                    cache.Remove(_pipelineAttributeFilterKeys[pipelineType]); 
                    cache[_pipelineInitializeKeys[pipelineType]] = members;
                } 
            }

            return members;
        } 

        ///  
        ///     Metadata merging is the second stage of our metadata pipeline.  This stage 
        ///     merges extended metdata with primary metadata, and stores it in
        ///     the cache if it is available. 
        /// 
        private static ICollection PipelineMerge(int pipelineType, ICollection primary, ICollection secondary, object instance, IDictionary cache)
        {
            // If there is no secondary collection, there is nothing to merge. 
            //
            if (secondary == null || secondary.Count == 0) 
            { 
                return primary;
            } 

            // Next, if we were given a cache, see if it has accurate data.
            //
            if (cache != null) 
            {
                ICollection mergeCache = cache[_pipelineMergeKeys[pipelineType]] as ICollection; 
                if (mergeCache != null && mergeCache.Count == (primary.Count + secondary.Count)) 
                {
                    // Walk the merge cache. 
                    IEnumerator mergeEnum = mergeCache.GetEnumerator();
                    IEnumerator primaryEnum = primary.GetEnumerator();
                    bool match = true;
 
                    while(primaryEnum.MoveNext() && mergeEnum.MoveNext())
                    { 
                        if (primaryEnum.Current != mergeEnum.Current) 
                        {
                            match = false; 
                            break;
                        }
                    }
 
                    if (match)
                    { 
                        IEnumerator secondaryEnum = secondary.GetEnumerator(); 

                        while(secondaryEnum.MoveNext() && mergeEnum.MoveNext()) 
                        {
                            if (secondaryEnum.Current != mergeEnum.Current)
                            {
                                match = false; 
                                break;
                            } 
                        } 
                    }
 
                    if (match)
                    {
                        return mergeCache;
                    } 
                }
            } 
 
            // Our cache didn't match.  We need to merge metadata and return
            // the merged copy.  We create an array list here, rather than 
            // an array, because we want successive sections of the
            // pipeline to be able to modify it.
            //
            ArrayList list = new ArrayList(primary.Count + secondary.Count); 
            foreach(object obj in primary)
            { 
                list.Add(obj); 
            }
            foreach(object obj in secondary) 
            {
                list.Add(obj);
            }
 
            if (cache != null)
            { 
                ICollection cacheValue; 

                switch(pipelineType) 
                {
                    case PIPELINE_ATTRIBUTES:
                        Attribute[] attrArray = new Attribute[list.Count];
                        list.CopyTo(attrArray, 0); 
                        cacheValue = new AttributeCollection(attrArray);
                        break; 
 
                    case PIPELINE_PROPERTIES:
                        PropertyDescriptor[] propArray = new PropertyDescriptor[list.Count]; 
                        list.CopyTo(propArray, 0);
                        cacheValue = new PropertyDescriptorCollection(propArray, true);
                        break;
 
                    case PIPELINE_EVENTS:
                        EventDescriptor[] eventArray = new EventDescriptor[list.Count]; 
                        list.CopyTo(eventArray, 0); 
                        cacheValue = new EventDescriptorCollection(eventArray, true);
                        break; 

                    default:
                        Debug.Fail("unknown pipeline type");
                        cacheValue = null; 
                        break;
                } 
 
                Trace("Pipeline : Merge results being cached for {0}", instance.GetType().Name);
                cache[_pipelineMergeKeys[pipelineType]] = cacheValue; 
                cache.Remove(_pipelineFilterKeys[pipelineType]);
                cache.Remove(_pipelineAttributeFilterKeys[pipelineType]);
            }
 
            return list;
        } 
 
        private static void RaiseRefresh(object component) {
            RefreshEventHandler handler = _refreshHandler; 

            if (handler != null)
            {
                handler(new RefreshEventArgs(component)); 
            }
        } 
 
        private static void RaiseRefresh(Type type) {
            RefreshEventHandler handler = _refreshHandler; 

            if (handler != null)
            {
                handler(new RefreshEventArgs(type)); 
            }
        } 
 
        /// 
        ///    Clears the properties and events for the specified 
        ///    component from the cache.
        /// 
        public static void Refresh(object component)
        { 
            #if DEBUG
            DebugTypeDescriptor.Refresh(component); 
            #endif 

            if (component == null) 
            {
                Debug.Fail("COMPAT:  Returning, but you should not pass null here");
                return;
            } 

            // Build up a list of type description providers for 
            // each type that is a derived type of the given 
            // object.  We will invalidate the metadata at
            // each of these levels. 

            Type type = component.GetType();
            bool found = false;
 
            lock(_providerTable)
            { 
                // ReflectTypeDescritionProvider is only bound to object, but we 
                // need go to through the entire table to try to find custom
                // providers.  If we find one, will clear our cache. 
                foreach(DictionaryEntry de in _providerTable)
                {
                    Type nodeType = de.Key as Type;
                    if (nodeType != null && type.IsAssignableFrom(nodeType) || nodeType == typeof(object)) 
                    {
                        TypeDescriptionNode node = (TypeDescriptionNode)de.Value; 
                        while(node != null && !(node.Provider is ReflectTypeDescriptionProvider)) 
                        {
                            found = true; 
                            node = node.Next;
                        }

                        if (node != null) 
                        {
                            ReflectTypeDescriptionProvider provider = (ReflectTypeDescriptionProvider)node.Provider; 
                            if (provider.IsPopulated(type)) 
                            {
                                found = true; 
                                provider.Refresh(type);
                            }
                        }
                    } 
                }
            } 
 
            // We need to clear our filter even if no typedescriptionprovider had data.
            // This is because if you call Refresh(instance1) and Refresh(instance2) 
            // and instance1 and instance2 are of the same type, you will end up not
            // actually deleting the dictionary cache on instance2 if you skip this
            // when you don't find a typedescriptionprovider.
            // However, we do not need to fire the event if we did not find any loaded 
            // typedescriptionprovider AND the cache is empty (if someone repeatedly calls
            // Refresh on an instance). 
 
            // Now, clear any cached data for the instance.
            // 
            IDictionary cache = GetCache(component);
            if (found || cache!= null)
            {
                if (cache != null) 
                {
                    Trace("Pipeline : Refresh clearing all pipeline caches"); 
                    for (int idx = 0; idx < _pipelineFilterKeys.Length; idx++) 
                    {
                        cache.Remove(_pipelineFilterKeys[idx]); 
                        cache.Remove(_pipelineMergeKeys[idx]);
                        cache.Remove(_pipelineAttributeFilterKeys[idx]);
                    }
 
                }
 
                Interlocked.Increment(ref _metadataVersion); 

                // And raise the event. 
                //
                RaiseRefresh(component);
            }
        } 

        ///  
        ///    Clears the properties and events for the specified type 
        ///    of component from the cache.
        ///  
        public static void Refresh(Type type)
        {
            #if DEBUG
            DebugTypeDescriptor.Refresh(type); 
            #endif
 
            if (type == null) 
            {
                Debug.Fail("COMPAT:  Returning, but you should not pass null here"); 
                return;
            }

            // Build up a list of type description providers for 
            // each type that is a derived type of the given
            // type.  We will invalidate the metadata at 
            // each of these levels. 

            bool found = false; 

            lock(_providerTable)
            {
                // ReflectTypeDescritionProvider is only bound to object, but we 
                // need go to through the entire table to try to find custom
                // providers.  If we find one, will clear our cache. 
                foreach(DictionaryEntry de in _providerTable) 
                {
                    Type nodeType = de.Key as Type; 
                    if (nodeType != null && type.IsAssignableFrom(nodeType) || nodeType == typeof(object))
                    {
                        TypeDescriptionNode node = (TypeDescriptionNode)de.Value;
                        while(node != null && !(node.Provider is ReflectTypeDescriptionProvider)) 
                        {
                            found = true; 
                            node = node.Next; 
                        }
 
                        if (node != null)
                        {
                            ReflectTypeDescriptionProvider provider = (ReflectTypeDescriptionProvider)node.Provider;
                            if (provider.IsPopulated(type)) 
                            {
                                found = true; 
                                provider.Refresh(type); 
                            }
                        } 
                    }
                }
            }
 
            // We only clear our filter and fire the refresh event if there was one or
            // more type description providers that were populated with metdata. 
            // This prevents us from doing a lot of extra work and raising 
            // a ton more events than we need to.
            // 
            if (found)
            {
                Interlocked.Increment(ref _metadataVersion);
 
                // And raise the event.
                // 
                RaiseRefresh(type); 
            }
        } 

        /// 
        ///    Clears the properties and events for the specified
        ///    module from the cache. 
        /// 
        public static void Refresh(Module module) 
        { 
            #if DEBUG
            DebugTypeDescriptor.Refresh(module); 
            #endif

            if (module == null)
            { 
                Debug.Fail("COMPAT:  Returning, but you should not pass null here");
                return; 
            } 

            // Build up a list of type description providers for 
            // each type that is a derived type of the given
            // object.  We will invalidate the metadata at
            // each of these levels.
            Hashtable refreshedTypes = null; 

            lock(_providerTable) 
            { 
                foreach(DictionaryEntry de in _providerTable)
                { 
                    Type nodeType = de.Key as Type;
                    if (nodeType != null && nodeType.Module.Equals(module) || nodeType == typeof(object))
                    {
                        TypeDescriptionNode node = (TypeDescriptionNode)de.Value; 
                        while(node != null && !(node.Provider is ReflectTypeDescriptionProvider))
                        { 
                            if (refreshedTypes == null) { 
                                refreshedTypes = new Hashtable();
                            } 
                            refreshedTypes[nodeType] = nodeType;
                            node = node.Next;
                        }
 
                        if (node != null)
                        { 
                            ReflectTypeDescriptionProvider provider = (ReflectTypeDescriptionProvider)node.Provider; 
                            Type[] populatedTypes = provider.GetPopulatedTypes(module);
 
                            foreach(Type populatedType in populatedTypes) {
                                provider.Refresh(populatedType);
                                if (refreshedTypes == null) {
                                    refreshedTypes = new Hashtable(); 
                                }
                                refreshedTypes[populatedType] = populatedType; 
                            } 
                        }
                    } 
                }
            }

            // And raise the event if types were refresh and handlers are attached. 
            //
            if (refreshedTypes != null && _refreshHandler != null) 
            { 
                foreach(Type t in refreshedTypes.Keys) {
                    RaiseRefresh(t); 
                }
            }
        }
 
        /// 
        ///    Clears the properties and events for the specified 
        ///    assembly from the cache. 
        /// 
        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Machine | ResourceScope.Assembly, ResourceScope.Machine | ResourceScope.Assembly)]
        public static void Refresh(Assembly assembly)
        {
            if (assembly == null) 
            {
                Debug.Fail("COMPAT:  Returning, but you should not pass null here"); 
                return; 
            }
 
            foreach (Module mod in assembly.GetModules())
            {
                Refresh(mod);
            } 

            // Debug type descriptor has the same code, so our call above will handle this. 
        } 

        ///  
        ///     The RemoveAssociation method removes an association with an object.
        /// 
        [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        public static void RemoveAssociation(object primary, object secondary)
        { 
            if (primary == null) 
            {
                throw new ArgumentNullException("primary"); 
            }

            if (secondary == null)
            { 
                throw new ArgumentNullException("secondary");
            } 
 
            Hashtable assocTable = _associationTable;
            if (assocTable != null) 
            {
                IList associations = (IList)assocTable[primary];
                if (associations != null)
                { 
                    lock(associations)
                    { 
                        for (int idx = associations.Count - 1; idx >= 0; idx--) 
                        {
                            // Look for an associated object that has a type that 
                            // matches the given type.
                            //
                            WeakReference weakRef = (WeakReference)associations[idx];
                            object secondaryItem = weakRef.Target; 
                            if (secondaryItem == null || secondaryItem == secondary)
                            { 
                                associations.RemoveAt(idx); 
                            }
                        } 
                    }
                }
            }
        } 

        ///  
        ///     The RemoveAssociations method removes all associations for a primary object. 
        /// 
        [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")] 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static void RemoveAssociations(object primary)
        {
            if (primary == null) 
            {
                throw new ArgumentNullException("primary"); 
            } 

            Hashtable assocTable = _associationTable; 
            if (assocTable != null)
            {
                assocTable.Remove(primary);
            } 
        }
 
        ///  
        ///     The RemoveProvider method removes a previously added type
        ///     description provider.  Removing a provider causes a Refresh 
        ///     event to be raised for the object or type the provider is
        ///     associated with.
        /// 
        [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")] 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static void RemoveProvider(TypeDescriptionProvider provider, Type type) 
        { 
            if (provider == null)
            { 
                throw new ArgumentNullException("provider");
            }

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

            // Walk the nodes until we find the right one, and then remove it. 
            NodeRemove(type, provider);
            RaiseRefresh(type);
        }
 
        /// 
        ///     The RemoveProvider method removes a previously added type 
        ///     description provider.  Removing a provider causes a Refresh 
        ///     event to be raised for the object or type the provider is
        ///     associated with. 
        /// 
        [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public static void RemoveProvider(TypeDescriptionProvider provider, object instance) 
        {
            if (provider == null) 
            { 
                throw new ArgumentNullException("provider");
            } 

            if (instance == null)
            {
                throw new ArgumentNullException("instance"); 
            }
 
            // Walk the nodes until we find the right one, and then remove it. 
            NodeRemove(instance, provider);
            RaiseRefresh(instance); 
        }

        /// 
        ///     This function takes a member descriptor and an attribute and determines whether 
        ///     the member satisfies the particular attribute.  This either means that the member
        ///     contains the attribute or the member does not contain the attribute and the default 
        ///     for the attribute matches the passed in attribute. 
        /// 
        private static bool ShouldHideMember(MemberDescriptor member, Attribute attribute) 
        {
            if (member == null || attribute == null)
            {
                return true; 
            }
 
            Attribute memberAttribute = member.Attributes[attribute.GetType()]; 
            if (memberAttribute == null)
            { 
                return !attribute.IsDefaultAttribute();
            }
            else
            { 
                return !(attribute.Match(memberAttribute));
            } 
        } 

        ///  
        ///     Sorts descriptors by name of the descriptor.
        /// 
        public static void SortDescriptorArray(IList infos)
        { 
            if (infos == null)
            { 
                throw new ArgumentNullException("infos"); 
            }
 
            ArrayList.Adapter(infos).Sort(MemberDescriptorComparer.Instance);
        }

        ///  
        ///     Internal tracing API for debugging type descriptor.
        ///  
        [Conditional("DEBUG")] 
        internal static void Trace(string message, params object[] args)
        { 
            Debug.WriteLineIf(TraceDescriptor.Enabled, string.Format(CultureInfo.InvariantCulture, "TypeDescriptor : {0}", string.Format(CultureInfo.InvariantCulture, message, args)));
        }

        ///  
        ///     This is a type description provider that adds the given
        ///     array of attributes to a class or instance, preserving the rest 
        ///     of the metadata in the process. 
        /// 
        private sealed class AttributeProvider : TypeDescriptionProvider 
        {
            Attribute[] _attrs;

            ///  
            ///     Creates a new attribute provider.
            ///  
            internal AttributeProvider(TypeDescriptionProvider existingProvider, params Attribute[] attrs) : base(existingProvider) 
            {
                _attrs = attrs; 
            }

            /// 
            ///     Creates a custom type descriptor that replaces the attributes. 
            /// 
            public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance) 
            { 
                return new AttributeTypeDescriptor(_attrs, base.GetTypeDescriptor(objectType, instance));
            } 

            /// 
            ///     Our custom type descriptor.
            ///  
            private class AttributeTypeDescriptor : CustomTypeDescriptor
            { 
                Attribute[]         _attributeArray; 

                ///  
                ///     Creates a new custom type descriptor that can merge
                ///     the provided set of attributes with the existing set.
                /// 
                internal AttributeTypeDescriptor(Attribute[] attrs, ICustomTypeDescriptor parent) : base(parent) 
                {
                    _attributeArray = attrs; 
                } 

                ///  
                ///     Retrieves the merged set of attributes.  We do not cache
                ///     this because there is always the possibility that someone
                ///     changed our parent provider's metadata.  TypeDescriptor
                ///     will cache this for us anyhow. 
                /// 
                public override AttributeCollection GetAttributes() 
                { 
                    Attribute[] finalAttr = null;
                    AttributeCollection existing = base.GetAttributes(); 
                    Attribute[] newAttrs = _attributeArray;
                    Attribute[] newArray = new Attribute[existing.Count + newAttrs.Length];
                    int actualCount = existing.Count;
                    existing.CopyTo(newArray, 0); 

                    for (int idx = 0; idx < newAttrs.Length; idx++) 
                    { 

                        Debug.Assert(newAttrs[idx] != null, "_attributes contains a null member"); 

                        // We must see if this attribute is already in the existing
                        // array.  If it is, we replace it.
                        bool match = false; 
                        for (int existingIdx = 0; existingIdx < existing.Count; existingIdx++)
                        { 
                            if (newArray[existingIdx].TypeId.Equals(newAttrs[idx].TypeId)) 
                            {
                                match = true; 
                                newArray[existingIdx] = newAttrs[idx];
                                break;
                            }
                        } 

                        if (!match) 
                        { 
                            newArray[actualCount++] = newAttrs[idx];
                        } 
                    }

                    // Now, if we collapsed some attributes, create a new array.
                    // 
                    if (actualCount < newArray.Length)
                    { 
                        finalAttr = new Attribute[actualCount]; 
                        Array.Copy(newArray, 0, finalAttr, 0, actualCount);
                    } 
                    else
                    {
                        finalAttr= newArray;
                    } 

                    return new AttributeCollection(finalAttr); 
                } 
            }
        } 

        /// 
        ///     This class is a type description provider that works with the IComNativeDescriptorHandler
        ///     interface. 
        /// 
        private sealed class ComNativeDescriptionProvider : TypeDescriptionProvider 
        { 
#pragma warning disable 618
            private IComNativeDescriptorHandler _handler; 

            internal ComNativeDescriptionProvider(IComNativeDescriptorHandler handler)
            {
                _handler = handler; 
            }
 
            ///  
            ///     Returns the COM handler object.
            ///  
            internal IComNativeDescriptorHandler Handler
            {
                get
                { 
                    return _handler;
                } 
                set 
                {
                    _handler = value; 
                }
            }
#pragma warning restore 618
 
            /// 
            ///     Implements GetTypeDescriptor.  This creates a custom type 
            ///     descriptor that walks the linked list for each of its calls. 
            /// 
 
            [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters")]
            public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
            {
                if (objectType == null) 
                {
                    throw new ArgumentNullException("objectType"); 
                } 

                if (instance == null) 
                {
                    return null;
                }
 
                if (!objectType.IsInstanceOfType(instance))
                { 
                    throw new ArgumentException("instance"); 
                }
 
                return new ComNativeTypeDescriptor(_handler, instance);
            }

            ///  
            ///     This type descriptor sits on top of a native
            ///     descriptor handler. 
            ///  
            private sealed class ComNativeTypeDescriptor : ICustomTypeDescriptor
            { 
#pragma warning disable 618
                private IComNativeDescriptorHandler _handler;
                private object _instance;
 
                /// 
                ///     Creates a new ComNativeTypeDescriptor. 
                ///  
                internal ComNativeTypeDescriptor(IComNativeDescriptorHandler handler, object instance)
                { 
                    _handler = handler;
                    _instance = instance;
                }
#pragma warning restore 618 

                ///  
                ///     ICustomTypeDescriptor implementation. 
                /// 
                AttributeCollection ICustomTypeDescriptor.GetAttributes() 
                {
                    return _handler.GetAttributes(_instance);
                }
 
                /// 
                ///     ICustomTypeDescriptor implementation. 
                ///  
                string ICustomTypeDescriptor.GetClassName()
                { 
                    return _handler.GetClassName(_instance);
                }

                ///  
                ///     ICustomTypeDescriptor implementation.
                ///  
                string ICustomTypeDescriptor.GetComponentName() 
                {
                    return null; 
                }

                /// 
                ///     ICustomTypeDescriptor implementation. 
                /// 
                TypeConverter ICustomTypeDescriptor.GetConverter() 
                { 
                    return _handler.GetConverter(_instance);
                } 

                /// 
                ///     ICustomTypeDescriptor implementation.
                ///  
                EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
                { 
                    return _handler.GetDefaultEvent(_instance); 
                }
 
                /// 
                ///     ICustomTypeDescriptor implementation.
                /// 
                PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() 
                {
                    return _handler.GetDefaultProperty(_instance); 
                } 

                ///  
                ///     ICustomTypeDescriptor implementation.
                /// 
                object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
                { 
                    return _handler.GetEditor(_instance, editorBaseType);
                } 
 
                /// 
                ///     ICustomTypeDescriptor implementation. 
                /// 
                EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
                {
                    return _handler.GetEvents(_instance); 
                }
 
                ///  
                ///     ICustomTypeDescriptor implementation.
                ///  
                EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
                {
                    return _handler.GetEvents(_instance, attributes);
                } 

                ///  
                ///     ICustomTypeDescriptor implementation. 
                /// 
                PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() 
                {
                    return _handler.GetProperties(_instance, null);
                }
 
                /// 
                ///     ICustomTypeDescriptor implementation. 
                ///  
                PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
                { 
                    return _handler.GetProperties(_instance, attributes);
                }

                ///  
                ///     ICustomTypeDescriptor implementation.
                ///  
                object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd) 
                {
                    return _instance; 
                }
            }
        }
 
        /// 
        ///     This is a simple class that is used to store a filtered 
        ///     set of members in an object's dictionary cache.  It is 
        ///     used by the PipelineAttributeFilter method.
        ///  
        private sealed class AttributeFilterCacheItem
        {
            private Attribute[] _filter;
            internal ICollection FilteredMembers; 

            internal AttributeFilterCacheItem(Attribute[] filter, ICollection filteredMembers) 
            { 
                _filter = filter;
                FilteredMembers = filteredMembers; 
            }

            internal bool IsValid(Attribute[] filter)
            { 
                if (_filter.Length != filter.Length) return false;
 
                for (int idx = 0; idx < filter.Length; idx++) { 
                    if (_filter[idx] != filter[idx]) {
                        return false; 
                    }
                }

                return true; 
            }
        } 
 
        /// 
        /// This small class contains cache information for the filter stage of our 
        /// caching algorithm.  It is used by the PipelineFilter method.
        /// 
        private sealed class FilterCacheItem {
            private ITypeDescriptorFilterService _filterService; 
            internal ICollection FilteredMembers;
 
            internal FilterCacheItem(ITypeDescriptorFilterService filterService, ICollection filteredMembers) { 
                _filterService = filterService;
                FilteredMembers = filteredMembers; 
            }

            internal bool IsValid(ITypeDescriptorFilterService filterService) {
                if (!Object.ReferenceEquals(_filterService, filterService)) return false; 
                return true;
            } 
        } 

        ///  
        ///     An unimplemented interface.  What is this?  It is an interface that nobody ever
        ///     implements, of course? Where and why would it be used?  Why, to find cross-process
        ///     remoted objects, of course!  If a well-known object comes in from a cross process
        ///     connection, the remoting layer does contain enough type information to determine 
        ///     if an object implements an interface.  It assumes that if you are going to cast
        ///     an object to an interface that you know what you're doing, and allows the cast, 
        ///     even for objects that DON'T actually implement the interface.  The error here 
        ///     is raised later when you make your first call on that interface pointer:  you
        ///     get a remoting exception. 
        ///
        ///     This is a big problem for code that does "is" and "as" checks to detect the
        ///     presence of an interface.  We do that all over the place here, so we do a check
        ///     during parameter validation to see if an object implements IUnimplemented.  If it 
        ///     does, we know that what we really have is a lying remoting proxy, and we bail.
        ///  
        private interface IUnimplemented {} 

        ///  
        ///     This comparer compares member descriptors for sorting.
        /// 
        private sealed class MemberDescriptorComparer : IComparer {
            public static readonly MemberDescriptorComparer Instance = new MemberDescriptorComparer(); 

            public int Compare(object left, object right) { 
                return string.Compare(((MemberDescriptor)left).Name, ((MemberDescriptor)right).Name, false, CultureInfo.InvariantCulture); 
            }
        } 

        /// 
        ///     This is a merged type descriptor that can merge the output of
        ///     a primary and secondary type descriptor.  If the primary doesn't 
        ///     provide the needed information, the request is passed on to the
        ///     secondary. 
        ///  
        private sealed class MergedTypeDescriptor : ICustomTypeDescriptor
        { 
            private ICustomTypeDescriptor _primary;
            private ICustomTypeDescriptor _secondary;

            ///  
            ///     Creates a new MergedTypeDescriptor.
            ///  
            internal MergedTypeDescriptor(ICustomTypeDescriptor primary, ICustomTypeDescriptor secondary) 
            {
                _primary = primary; 
                _secondary = secondary;
            }

            ///  
            ///     ICustomTypeDescriptor implementation.
            ///  
            AttributeCollection ICustomTypeDescriptor.GetAttributes() 
            {
                AttributeCollection attrs = _primary.GetAttributes(); 
                if (attrs == null)
                {
                    attrs = _secondary.GetAttributes();
                } 

                Debug.Assert(attrs != null, "Someone should have handled this"); 
                return attrs; 
            }
 
            /// 
            ///     ICustomTypeDescriptor implementation.
            /// 
            string ICustomTypeDescriptor.GetClassName() 
            {
                string className = _primary.GetClassName(); 
                if (className == null) 
                {
                    className = _secondary.GetClassName(); 
                }

                Debug.Assert(className != null, "Someone should have handled this");
                return className; 
            }
 
            ///  
            ///     ICustomTypeDescriptor implementation.
            ///  
            string ICustomTypeDescriptor.GetComponentName()
            {
                string name = _primary.GetComponentName();
                if (name == null) 
                {
                    name = _secondary.GetComponentName(); 
                } 

                return name; 
            }

            /// 
            ///     ICustomTypeDescriptor implementation. 
            /// 
            TypeConverter ICustomTypeDescriptor.GetConverter() 
            { 
                TypeConverter converter = _primary.GetConverter();
                if (converter == null) 
                {
                    converter = _secondary.GetConverter();
                }
 
                Debug.Assert(converter != null, "Someone should have handled this");
                return converter; 
            } 

            ///  
            ///     ICustomTypeDescriptor implementation.
            /// 
            EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
            { 
                EventDescriptor evt = _primary.GetDefaultEvent();
                if (evt == null) 
                { 
                    evt = _secondary.GetDefaultEvent();
                } 

                return evt;
            }
 
            /// 
            ///     ICustomTypeDescriptor implementation. 
            ///  
            PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
            { 
                PropertyDescriptor prop = _primary.GetDefaultProperty();
                if (prop == null)
                {
                    prop = _secondary.GetDefaultProperty(); 
                }
 
                return prop; 
            }
 
            /// 
            ///     ICustomTypeDescriptor implementation.
            /// 
            object ICustomTypeDescriptor.GetEditor(Type editorBaseType) 
            {
                if (editorBaseType == null) 
                { 
                    throw new ArgumentNullException("editorBaseType");
                } 

                object editor = _primary.GetEditor(editorBaseType);
                if (editor == null)
                { 
                    editor = _secondary.GetEditor(editorBaseType);
                } 
 
                return editor;
            } 

            /// 
            ///     ICustomTypeDescriptor implementation.
            ///  
            EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
            { 
                EventDescriptorCollection events = _primary.GetEvents(); 
                if (events == null)
                { 
                    events = _secondary.GetEvents();
                }

                Debug.Assert(events != null, "Someone should have handled this"); 
                return events;
            } 
 
            /// 
            ///     ICustomTypeDescriptor implementation. 
            /// 
            EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
            {
                EventDescriptorCollection events = _primary.GetEvents(attributes); 
                if (events == null)
                { 
                    events = _secondary.GetEvents(attributes); 
                }
 
                Debug.Assert(events != null, "Someone should have handled this");
                return events;
            }
 
            /// 
            ///     ICustomTypeDescriptor implementation. 
            ///  
            PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
            { 
                PropertyDescriptorCollection properties = _primary.GetProperties();
                if (properties == null)
                {
                    properties = _secondary.GetProperties(); 
                }
 
                Debug.Assert(properties != null, "Someone should have handled this"); 
                return properties;
            } 

            /// 
            ///     ICustomTypeDescriptor implementation.
            ///  
            PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
            { 
                PropertyDescriptorCollection properties = _primary.GetProperties(attributes); 
                if (properties == null)
                { 
                    properties = _secondary.GetProperties(attributes);
                }

                Debug.Assert(properties != null, "Someone should have handled this"); 
                return properties;
            } 
 
            /// 
            ///     ICustomTypeDescriptor implementation. 
            /// 
            object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
            {
                object owner = _primary.GetPropertyOwner(pd); 
                if (owner == null)
                { 
                    owner = _secondary.GetPropertyOwner(pd); 
                }
 
                return owner;
            }
        }
 
        /// 
        ///     This is a linked list node that is comprised of a type 
        ///     description provider.  Each node contains a Next pointer 
        ///     to the next node in the list and also a Provider pointer
        ///     which contains the type description provider this node 
        ///     represents.  The implementation of TypeDescriptionProvider
        ///     that the node provides simply invokes the corresponding
        ///     method on the node's provider.
        ///  
        private sealed class TypeDescriptionNode : TypeDescriptionProvider
        { 
            internal TypeDescriptionNode                Next; 
            internal TypeDescriptionProvider   Provider;
 
            /// 
            ///     Creates a new type description node.
            /// 
            internal TypeDescriptionNode(TypeDescriptionProvider provider) 
            {
                Provider = provider; 
            } 

            ///  
            ///     Implements CreateInstance.  This just walks the linked list
            ///     looking for someone who implements the call.
            /// 
            public override object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args) 
            {
                if (objectType == null) 
                { 
                    throw new ArgumentNullException("objectType");
                } 

                if (argTypes != null)
                {
                    if (args == null) 
                    {
                        throw new ArgumentNullException("args"); 
                    } 

                    if (argTypes.Length != args.Length) 
                    {
                        throw new ArgumentException(SR.GetString(SR.TypeDescriptorArgsCountMismatch));
                    }
                } 

                return Provider.CreateInstance(provider, objectType, argTypes, args); 
            } 

            ///  
            ///     Implements GetCache.  This just walks the linked
            ///     list looking for someone who implements the call.
            /// 
            public override IDictionary GetCache(object instance) 
            {
                if (instance == null) 
                { 
                    throw new ArgumentNullException("instance");
                } 

                return Provider.GetCache(instance);
            }
 
            /// 
            ///     Implements GetExtendedTypeDescriptor.  This creates a custom type 
            ///     descriptor that walks the linked list for each of its calls. 
            /// 
            public override ICustomTypeDescriptor GetExtendedTypeDescriptor(object instance) 
            {
                if (instance == null)
                {
                    throw new ArgumentNullException("instance"); 
                }
 
                return new DefaultExtendedTypeDescriptor(this, instance); 
            }
 
            /// 
            ///     The name of the specified component, or null if the component has no name.
            ///     In many cases this will return the same value as GetComponentName. If the
            ///     component resides in a nested container or has other nested semantics, it may 
            ///     return a different fully qualfied name.
            /// 
            ///     If not overridden, the default implementation of this method will call 
            ///     GetTypeDescriptor.GetComponentName.
            ///  
            public override string GetFullComponentName(object component)
            {
                if (component == null)
                { 
                    throw new ArgumentNullException("component");
                } 
 
                return Provider.GetFullComponentName(component);
            } 

            /// 
            ///     Implements GetReflectionType.  This just walks the linked list
            ///     looking for someone who implements the call. 
            /// 
            public override Type GetReflectionType(Type objectType, object instance) 
            { 
                if (objectType == null)
                { 
                    throw new ArgumentNullException("objectType");
                }

                return Provider.GetReflectionType(objectType, instance); 
            }
 
            ///  
            ///     Implements GetTypeDescriptor.  This creates a custom type
            ///     descriptor that walks the linked list for each of its calls. 
            /// 

            [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters")]
            public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance) 
            {
                if (objectType == null) 
                { 
                    throw new ArgumentNullException("objectType");
                } 

                if (instance != null && !objectType.IsInstanceOfType(instance))
                {
                    throw new ArgumentException("instance"); 
                }
 
                return new DefaultTypeDescriptor(this, objectType, instance); 
            }
 
            /// 
            ///     A type descriptor for extended types.  This type descriptor
            ///     looks at the head node in the linked list.
            ///  
            private struct DefaultExtendedTypeDescriptor : ICustomTypeDescriptor
            { 
                private TypeDescriptionNode _node; 
                private object              _instance;
 
                /// 
                ///     Creates a new WalkingExtendedTypeDescriptor.
                /// 
                internal DefaultExtendedTypeDescriptor(TypeDescriptionNode node, object instance) 
                {
                    _node = node; 
                    _instance = instance; 
                }
 
                /// 
                ///     ICustomTypeDescriptor implementation.
                /// 
                AttributeCollection ICustomTypeDescriptor.GetAttributes() 
                {
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider. 
                    // If so, we can call on it directly rather than creating another 
                    // custom type descriptor
 
                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;

                    if (rp != null) { 
                        return rp.GetExtendedAttributes(_instance);
                    } 
 
                    ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
                    if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor")); 
                    AttributeCollection attrs = desc.GetAttributes();
                    if (attrs == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetAttributes"));
                    return attrs;
                } 

                ///  
                ///     ICustomTypeDescriptor implementation. 
                /// 
                string ICustomTypeDescriptor.GetClassName() 
                {
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another
                    // custom type descriptor 

                    TypeDescriptionProvider p = _node.Provider; 
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider; 

                    if (rp != null) { 
                        return rp.GetExtendedClassName(_instance);
                    }

                    ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance); 
                    if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
                    string name = desc.GetClassName(); 
                    if (name == null) name = _instance.GetType().FullName; 
                    return name;
                } 

                /// 
                ///     ICustomTypeDescriptor implementation.
                ///  
                string ICustomTypeDescriptor.GetComponentName()
                { 
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider. 
                    // If so, we can call on it directly rather than creating another
                    // custom type descriptor 

                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
 
                    if (rp != null) {
                        return rp.GetExtendedComponentName(_instance); 
                    } 

                    ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance); 
                    if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
                    return desc.GetComponentName();
                }
 
                /// 
                ///     ICustomTypeDescriptor implementation. 
                ///  
                TypeConverter ICustomTypeDescriptor.GetConverter()
                { 
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another
                    // custom type descriptor
 
                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider; 
 
                    if (rp != null) {
                        return rp.GetExtendedConverter(_instance); 
                    }

                    ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
                    if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor")); 
                    TypeConverter converter = desc.GetConverter();
                    if (converter == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetConverter")); 
                    return converter; 
                }
 
                /// 
                ///     ICustomTypeDescriptor implementation.
                /// 
                EventDescriptor ICustomTypeDescriptor.GetDefaultEvent() 
                {
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider. 
                    // If so, we can call on it directly rather than creating another 
                    // custom type descriptor
 
                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;

                    if (rp != null) { 
                        return rp.GetExtendedDefaultEvent(_instance);
                    } 
 
                    ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
                    if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor")); 
                    return desc.GetDefaultEvent();
                }

                ///  
                ///     ICustomTypeDescriptor implementation.
                ///  
                PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() 
                {
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider. 
                    // If so, we can call on it directly rather than creating another
                    // custom type descriptor

                    TypeDescriptionProvider p = _node.Provider; 
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
 
                    if (rp != null) { 
                        return rp.GetExtendedDefaultProperty(_instance);
                    } 

                    ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
                    if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
                    return desc.GetDefaultProperty(); 
                }
 
                ///  
                ///     ICustomTypeDescriptor implementation.
                ///  
                object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
                {
                    if (editorBaseType == null)
                    { 
                        throw new ArgumentNullException("editorBaseType");
                    } 
 
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another 
                    // custom type descriptor

                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider; 

                    if (rp != null) { 
                        return rp.GetExtendedEditor(_instance, editorBaseType); 
                    }
 
                    ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
                    if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
                    return desc.GetEditor(editorBaseType);
                } 

                ///  
                ///     ICustomTypeDescriptor implementation. 
                /// 
                EventDescriptorCollection ICustomTypeDescriptor.GetEvents() 
                {
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another
                    // custom type descriptor 

                    TypeDescriptionProvider p = _node.Provider; 
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider; 

                    if (rp != null) { 
                        return rp.GetExtendedEvents(_instance);
                    }

                    ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance); 
                    if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
                    EventDescriptorCollection events = desc.GetEvents(); 
                    if (events == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetEvents")); 
                    return events;
                } 

                /// 
                ///     ICustomTypeDescriptor implementation.
                ///  
                EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
                { 
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider. 
                    // If so, we can call on it directly rather than creating another
                    // custom type descriptor 

                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
 
                    if (rp != null) {
                        // There is no need to filter these events.  For extended objects, they 
                        // are accessed through our pipeline code, which always filters before 
                        // returning.  So any filter we do here is redundant.  Note that we do
                        // pass a valid filter to a custom descriptor so it can optimize if it wants. 
                        EventDescriptorCollection events = rp.GetExtendedEvents(_instance);
                        return events;
                    }
 
                    ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
                    if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor")); 
                    EventDescriptorCollection evts = desc.GetEvents(attributes); 
                    if (evts == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetEvents"));
                    return evts; 
                }

                /// 
                ///     ICustomTypeDescriptor implementation. 
                /// 
                PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() 
                { 
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another 
                    // custom type descriptor

                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider; 

                    if (rp != null) { 
                        return rp.GetExtendedProperties(_instance); 
                    }
 
                    ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
                    if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
                    PropertyDescriptorCollection properties = desc.GetProperties();
                    if (properties == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetProperties")); 
                    return properties;
                } 
 
                /// 
                ///     ICustomTypeDescriptor implementation. 
                /// 
                PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
                {
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider. 
                    // If so, we can call on it directly rather than creating another
                    // custom type descriptor 
 
                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider; 

                    if (rp != null) {
                        // There is no need to filter these properties.  For extended objects, they
                        // are accessed through our pipeline code, which always filters before 
                        // returning.  So any filter we do here is redundant.  Note that we do
                        // pass a valid filter to a custom descriptor so it can optimize if it wants. 
                        PropertyDescriptorCollection props = rp.GetExtendedProperties(_instance); 
                        return props;
                    } 

                    ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance);
                    if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
                    PropertyDescriptorCollection properties = desc.GetProperties(attributes); 
                    if (properties == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetProperties"));
                    return properties; 
                } 

                ///  
                ///     ICustomTypeDescriptor implementation.
                /// 
                object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
                { 
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another 
                    // custom type descriptor 

                    TypeDescriptionProvider p = _node.Provider; 
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;

                    if (rp != null) {
                        return rp.GetExtendedPropertyOwner(_instance, pd); 
                    }
 
                    ICustomTypeDescriptor desc = p.GetExtendedTypeDescriptor(_instance); 
                    if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetExtendedTypeDescriptor"));
                    object owner = desc.GetPropertyOwner(pd); 
                    if (owner == null) owner = _instance;
                    return owner;
                }
            } 

            ///  
            ///     The default type descriptor. 
            /// 
            private struct DefaultTypeDescriptor : ICustomTypeDescriptor 
            {
                private TypeDescriptionNode _node;
                private Type                _objectType;
                private object              _instance; 

                ///  
                ///     Creates a new WalkingTypeDescriptor. 
                /// 
                internal DefaultTypeDescriptor(TypeDescriptionNode node, Type objectType, object instance) 
                {
                    _node = node;
                    _objectType = objectType;
                    _instance = instance; 
                }
 
                ///  
                ///     ICustomTypeDescriptor implementation.
                ///  
                AttributeCollection ICustomTypeDescriptor.GetAttributes()
                {
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another 
                    // custom type descriptor
 
                    TypeDescriptionProvider p = _node.Provider; 
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
                    AttributeCollection attrs; 

                    if (rp != null) {
                        attrs = rp.GetAttributes(_objectType);
                    } 
                    else {
                        ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance); 
                        if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor")); 
                        attrs = desc.GetAttributes();
                        if (attrs == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetAttributes")); 
                    }

                    return attrs;
                } 

                ///  
                ///     ICustomTypeDescriptor implementation. 
                /// 
                string ICustomTypeDescriptor.GetClassName() 
                {
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another
                    // custom type descriptor 

                    TypeDescriptionProvider p = _node.Provider; 
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider; 
                    string name;
 
                    if (rp != null) {
                        name = rp.GetClassName(_objectType);
                    }
                    else { 
                        ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
                        if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor")); 
                        name = desc.GetClassName(); 
                        if (name == null) name = _objectType.FullName;
                    } 

                    return name;
                }
 
                /// 
                ///     ICustomTypeDescriptor implementation. 
                ///  
                string ICustomTypeDescriptor.GetComponentName()
                { 
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another
                    // custom type descriptor
 
                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider; 
                    string name; 

                    if (rp != null) { 
                        name = rp.GetComponentName(_objectType, _instance);
                    }
                    else {
                        ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance); 
                        if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
                        name = desc.GetComponentName(); 
                    } 

                    return name; 
                }

                /// 
                ///     ICustomTypeDescriptor implementation. 
                /// 
                TypeConverter ICustomTypeDescriptor.GetConverter() 
                { 
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another 
                    // custom type descriptor

                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider; 
                    TypeConverter converter;
 
                    if (rp != null) { 
                        converter = rp.GetConverter(_objectType, _instance);
                    } 
                    else {
                        ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
                        if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
                        converter = desc.GetConverter(); 
                        if (converter == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetConverter"));
                    } 
 
                    return converter;
                } 

                /// 
                ///     ICustomTypeDescriptor implementation.
                ///  
                EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
                { 
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider. 
                    // If so, we can call on it directly rather than creating another
                    // custom type descriptor 

                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
                    EventDescriptor defaultEvent; 

                    if (rp != null) { 
                        defaultEvent = rp.GetDefaultEvent(_objectType, _instance); 
                    }
                    else { 
                        ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
                        if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
                        defaultEvent = desc.GetDefaultEvent();
                    } 

                    return defaultEvent; 
                } 

                ///  
                ///     ICustomTypeDescriptor implementation.
                /// 
                PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
                { 
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another 
                    // custom type descriptor 

                    TypeDescriptionProvider p = _node.Provider; 
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
                    PropertyDescriptor defaultProperty;

                    if (rp != null) { 
                        defaultProperty = rp.GetDefaultProperty(_objectType, _instance);
                    } 
                    else { 
                        ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
                        if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor")); 
                        defaultProperty = desc.GetDefaultProperty();
                    }

                    return defaultProperty; 
                }
 
                ///  
                ///     ICustomTypeDescriptor implementation.
                ///  
                object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
                {
                    if (editorBaseType == null)
                    { 
                        throw new ArgumentNullException("editorBaseType");
                    } 
 
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another 
                    // custom type descriptor

                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider; 
                    object editor;
 
                    if (rp != null) { 
                        editor = rp.GetEditor(_objectType, _instance, editorBaseType);
                    } 
                    else {
                        ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
                        if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
                        editor = desc.GetEditor(editorBaseType); 
                    }
 
                    return editor; 
                }
 
                /// 
                ///     ICustomTypeDescriptor implementation.
                /// 
                EventDescriptorCollection ICustomTypeDescriptor.GetEvents() 
                {
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider. 
                    // If so, we can call on it directly rather than creating another 
                    // custom type descriptor
 
                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
                    EventDescriptorCollection events;
 
                    if (rp != null) {
                        events = rp.GetEvents(_objectType); 
                    } 
                    else {
                        ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance); 
                        if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
                        events = desc.GetEvents();
                        if (events == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetEvents"));
                    } 

                    return events; 
                } 

                ///  
                ///     ICustomTypeDescriptor implementation.
                /// 
                EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
                { 
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another 
                    // custom type descriptor 

                    TypeDescriptionProvider p = _node.Provider; 
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
                    EventDescriptorCollection events;

                    if (rp != null) { 
                        events = rp.GetEvents(_objectType);
                    } 
                    else { 
                        ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
                        if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor")); 
                        events = desc.GetEvents(attributes);
                        if (events == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetEvents"));
                    }
 
                    return events;
                } 
 
                /// 
                ///     ICustomTypeDescriptor implementation. 
                /// 
                PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
                {
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider. 
                    // If so, we can call on it directly rather than creating another
                    // custom type descriptor 
 
                    TypeDescriptionProvider p = _node.Provider;
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider; 
                    PropertyDescriptorCollection properties;

                    if (rp != null) {
                        properties = rp.GetProperties(_objectType); 
                    }
                    else { 
                        ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance); 
                        if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor"));
                        properties = desc.GetProperties(); 
                        if (properties == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetProperties"));
                    }

                    return properties; 
                }
 
                ///  
                ///     ICustomTypeDescriptor implementation.
                ///  
                PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
                {
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another 
                    // custom type descriptor
 
                    TypeDescriptionProvider p = _node.Provider; 
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider;
                    PropertyDescriptorCollection properties; 

                    if (rp != null) {
                        properties = rp.GetProperties(_objectType);
                    } 
                    else {
                        ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance); 
                        if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor")); 
                        properties = desc.GetProperties(attributes);
                        if (properties == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetProperties")); 
                    }

                    return properties;
                } 

                ///  
                ///     ICustomTypeDescriptor implementation. 
                /// 
                object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd) 
                {
                    // Check to see if the provider we get is a ReflectTypeDescriptionProvider.
                    // If so, we can call on it directly rather than creating another
                    // custom type descriptor 

                    TypeDescriptionProvider p = _node.Provider; 
                    ReflectTypeDescriptionProvider rp = p as ReflectTypeDescriptionProvider; 
                    object owner;
 
                    if (rp != null) {
                        owner = rp.GetPropertyOwner(_objectType, _instance, pd);
                    }
                    else { 
                        ICustomTypeDescriptor desc = p.GetTypeDescriptor(_objectType, _instance);
                        if (desc == null) throw new InvalidOperationException(SR.GetString(SR.TypeDescriptorProviderError, _node.Provider.GetType().FullName, "GetTypeDescriptor")); 
                        owner = desc.GetPropertyOwner(pd); 
                        if (owner == null) owner = _instance;
                    } 

                    return owner;
                }
            } 
        }
 
        ///  
        ///     This is a simple internal type that allows external parties
        ///     to public ina custom type description provider for COM 
        ///     objects.
        /// 
        [TypeDescriptionProvider("System.Windows.Forms.ComponentModel.Com2Interop.ComNativeDescriptor, " + AssemblyRef.SystemWindowsForms)]
        private sealed class TypeDescriptorComObject 
        {
        } 
    } 
}
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

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