Inheritance: TypeDescriptionProvider
        private void FillSingleMethodAttribute(MethodInfo realMethodInfo, IList attributes)
        {
            string       methodName         = realMethodInfo.Name;
            BindingFlags bindingFlags       = BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly;
            Type         currentReflectType = realMethodInfo.ReflectedType;

            Debug.Assert(currentReflectType != null, "currentReflectType cannot be null");

            // First, calculate the depth of the object hierarchy.  We do this so we can do a single
            // object create for an array of attributes.
            //
            int depth = 0;

            while (currentReflectType != null && currentReflectType != typeof(object))
            {
                depth++;
                currentReflectType = currentReflectType.GetTypeInfo().BaseType;
            }

            if (depth > 0)
            {
                // Now build up an array in reverse order
                //
                currentReflectType = realMethodInfo.ReflectedType;
                Attribute[][] attributeStack = new Attribute[depth][];

                while (currentReflectType != null && currentReflectType != typeof(object))
                {
                    // Fill in our member info so we can get at the custom attributes.
                    //
                    MemberInfo memberInfo = currentReflectType.GetMethod(methodName, bindingFlags);

                    // Get custom attributes for the member info.
                    //
                    if (memberInfo != null)
                    {
                        attributeStack[--depth] = ReflectTypeDescriptionProvider.ReflectGetAttributes(memberInfo);
                    }

                    // Ready for the next loop iteration.
                    //
                    currentReflectType = currentReflectType.GetTypeInfo().BaseType;
                }

                // Now trawl the attribute stack so that we add attributes
                // from base class to most derived.
                //
                foreach (Attribute[] attributeArray in attributeStack)
                {
                    if (attributeArray != null)
                    {
                        foreach (Attribute attr in attributeArray)
                        {
                            attributes.Add(attr);
                        }
                    }
                }
            }
        }
示例#2
0
            /// <summary>
            ///     Retrieves the type converter.  If instance is non-null,
            ///     it will be used to retrieve attributes.  Otherwise, _type
            ///     will be used.
            /// </summary>
            internal TypeConverter GetConverter(object instance)
            {
                TypeConverterAttribute typeAttr = null;

                // For instances, the design time object for them may want to redefine the
                // attributes.  So, we search the attribute here based on the instance.  If found,
                // we then search on the same attribute based on type.  If the two don't match, then
                // we cannot cache the value and must re-create every time.  It is rare for a designer
                // to override these attributes, so we want to be smart here.
                //
                if (instance != null)
                {
                    typeAttr = (TypeConverterAttribute)TypeDescriptor.GetAttributes(_type)[typeof(TypeConverterAttribute)];
                    TypeConverterAttribute instanceAttr = (TypeConverterAttribute)TypeDescriptor.GetAttributes(instance)[typeof(TypeConverterAttribute)];
                    if (typeAttr != instanceAttr)
                    {
                        Type converterType = GetTypeFromName(instanceAttr.ConverterTypeName);
                        if (converterType != null && typeof(TypeConverter).GetTypeInfo().IsAssignableFrom(converterType))
                        {
                            return((TypeConverter)ReflectTypeDescriptionProvider.CreateInstance(converterType, _type));
                        }
                    }
                }

                // If we got here, we return our type-based converter.
                //
                if (_converter == null)
                {
                    if (typeAttr == null)
                    {
                        typeAttr = (TypeConverterAttribute)TypeDescriptor.GetAttributes(_type)[typeof(TypeConverterAttribute)];
                    }

                    if (typeAttr != null)
                    {
                        Type converterType = GetTypeFromName(typeAttr.ConverterTypeName);
                        if (converterType != null && typeof(TypeConverter).GetTypeInfo().IsAssignableFrom(converterType))
                        {
                            _converter = (TypeConverter)ReflectTypeDescriptionProvider.CreateInstance(converterType, _type);
                        }
                    }

                    if (_converter == null)
                    {
                        // We did not get a converter.  Traverse up the base class chain until
                        // we find one in the stock hashtable.
                        //
                        _converter = (TypeConverter)ReflectTypeDescriptionProvider.SearchIntrinsicTable(IntrinsicTypeConverters, _type);
                        Debug.Assert(_converter != null, "There is no intrinsic setup in the hashtable for the Object type");
                    }
                }

                return(_converter);
            }
        private void FillEventInfoAttribute(EventInfo realEventInfo, IList attributes)
        {
            string       eventName          = realEventInfo.Name;
            BindingFlags bindingFlags       = BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly;
            Type         currentReflectType = realEventInfo.ReflectedType !;

            Debug.Assert(currentReflectType != null, "currentReflectType cannot be null");
            Debug.Assert(currentReflectType.IsAssignableFrom(_componentClass), "currentReflectType must be in _componentClass's hierarchy");
            int depth = 0;

            // First, calculate the depth of the object hierarchy. We do this so we can do a single
            // object create for an array of attributes.
            while (currentReflectType != typeof(object))
            {
                depth++;
                currentReflectType = currentReflectType.BaseType !;
            }

            if (depth > 0)
            {
                // Now build up an array in reverse order
                currentReflectType = realEventInfo.ReflectedType !;
                Attribute[][] attributeStack = new Attribute[depth][];

                while (currentReflectType != typeof(object))
                {
                    // Fill in our member info so we can get at the custom attributes.
                    MemberInfo?memberInfo = currentReflectType !.GetEvent(eventName, bindingFlags);

                    // Get custom attributes for the member info.
                    if (memberInfo != null)
                    {
                        attributeStack[--depth] = ReflectTypeDescriptionProvider.ReflectGetAttributes(memberInfo);
                    }

                    // Ready for the next loop iteration.
                    currentReflectType = currentReflectType.BaseType !;
                }

                // Now trawl the attribute stack so that we add attributes
                // from base class to most derived.
                foreach (Attribute[] attributeArray in attributeStack)
                {
                    if (attributeArray != null)
                    {
                        foreach (Attribute attr in attributeArray)
                        {
                            attributes.Add(attr);
                        }
                    }
                }
            }
        }
        public static void ClearCache(Type[]?types)
        {
            // ReflectTypeDescriptionProvider maintains global caches on top of reflection.
            // Clear those.
            ReflectTypeDescriptionProvider.ClearReflectionCaches();

            // Each type descriptor may also cache reflection-based state that it gathered
            // from ReflectTypeDescriptionProvider.  Clear those as well.
            if (types is not null)
            {
                foreach (Type type in types)
                {
                    TypeDescriptor.Refresh(type);
                }
            }
            else
            {
                foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
                {
                    TypeDescriptor.Refresh(assembly);
                }
            }
        }
        private void FillSingleMethodAttribute(MethodInfo realMethodInfo, IList attributes)
        {
            string       name          = realMethodInfo.Name;
            BindingFlags bindingAttr   = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;
            Type         reflectedType = realMethodInfo.ReflectedType;
            int          num           = 0;

            while ((reflectedType != null) && (reflectedType != typeof(object)))
            {
                num++;
                reflectedType = reflectedType.BaseType;
            }
            if (num > 0)
            {
                reflectedType = realMethodInfo.ReflectedType;
                Attribute[][] attributeArray = new Attribute[num][];
                while ((reflectedType != null) && (reflectedType != typeof(object)))
                {
                    MemberInfo method = reflectedType.GetMethod(name, bindingAttr);
                    if (method != null)
                    {
                        attributeArray[--num] = ReflectTypeDescriptionProvider.ReflectGetAttributes(method);
                    }
                    reflectedType = reflectedType.BaseType;
                }
                foreach (Attribute[] attributeArray2 in attributeArray)
                {
                    if (attributeArray2 != null)
                    {
                        foreach (Attribute attribute in attributeArray2)
                        {
                            attributes.Add(attribute);
                        }
                    }
                }
            }
        }
示例#6
0
            /// <summary>
            ///     Retrieves custom attributes.
            /// </summary>
            internal AttributeCollection GetAttributes()
            {
                // Worst case collision scenario:  we don't want the perf hit
                // of taking a lock, so if we collide we will query for
                // attributes twice.  Not a big deal.
                //
                if (_attributes == null)
                {
                    // Obtaining attributes follows a very critical order: we must take care that
                    // we merge attributes the right way.  Consider this:
                    //
                    // [A4]
                    // interface IBase;
                    //
                    // [A3]
                    // interface IDerived;
                    //
                    // [A2]
                    // class Base : IBase;
                    //
                    // [A1]
                    // class Derived : Base, IDerived
                    //
                    // Calling GetAttributes on type Derived must merge attributes in the following
                    // order:  A1 - A4.  Interfaces always lose to types, and interfaces and types
                    // must be merged in the same order.  At the same time, we must be careful
                    // that we don't always go through reflection here, because someone could have
                    // created a custom provider for a type.  Because there is only one instance
                    // of ReflectTypeDescriptionProvider created for typeof(object), if our code
                    // is invoked here we can be sure that there is no custom provider for
                    // _type all the way up the base class chain.
                    // We cannot be sure that there is no custom provider for
                    // interfaces that _type implements, however, because they are not derived
                    // from _type.  So, for interfaces, we must go through TypeDescriptor
                    // again to get the interfaces attributes.

                    // Get the type's attributes. This does not recurse up the base class chain.
                    // We append base class attributes to this array so when walking we will
                    // walk from Length - 1 to zero.
                    //
                    Attribute[] attrArray = ReflectTypeDescriptionProvider.ReflectGetAttributes(_type);
                    Type        baseType  = _type.GetTypeInfo().BaseType;

                    while (baseType != null && baseType != typeof(object))
                    {
                        Attribute[] baseArray = ReflectTypeDescriptionProvider.ReflectGetAttributes(baseType);
                        Attribute[] temp      = new Attribute[attrArray.Length + baseArray.Length];
                        Array.Copy(attrArray, 0, temp, 0, attrArray.Length);
                        Array.Copy(baseArray, 0, temp, attrArray.Length, baseArray.Length);
                        attrArray = temp;
                        baseType  = baseType.GetTypeInfo().BaseType;
                    }

                    // Next, walk the type's interfaces.  We append these to
                    // the attribute array as well.
                    //
                    int    ifaceStartIdx = attrArray.Length;
                    Type[] interfaces    = _type.GetTypeInfo().GetInterfaces();
                    for (int idx = 0; idx < interfaces.Length; idx++)
                    {
                        Type iface = interfaces[idx];

                        // only do this for public interfaces.
                        //
                        if ((iface.GetTypeInfo().Attributes & (TypeAttributes.Public | TypeAttributes.NestedPublic)) != 0)
                        {
                            // No need to pass an instance into GetTypeDescriptor here because, if someone provided a custom
                            // provider based on object, it already would have hit.
                            AttributeCollection ifaceAttrs = TypeDescriptor.GetAttributes(iface);
                            if (ifaceAttrs.Count > 0)
                            {
                                Attribute[] temp = new Attribute[attrArray.Length + ifaceAttrs.Count];
                                Array.Copy(attrArray, 0, temp, 0, attrArray.Length);
                                ifaceAttrs.CopyTo(temp, attrArray.Length);
                                attrArray = temp;
                            }
                        }
                    }

                    // Finally, put all these attributes in a dictionary and filter out the duplicates.
                    //
                    OrderedDictionary attrDictionary = new OrderedDictionary(attrArray.Length);

                    for (int idx = 0; idx < attrArray.Length; idx++)
                    {
                        bool addAttr = true;
                        if (idx >= ifaceStartIdx)
                        {
                            for (int ifaceSkipIdx = 0; ifaceSkipIdx < s_skipInterfaceAttributeList.Length; ifaceSkipIdx++)
                            {
                                if (s_skipInterfaceAttributeList[ifaceSkipIdx].GetTypeInfo().IsInstanceOfType(attrArray[idx]))
                                {
                                    addAttr = false;
                                    break;
                                }
                            }
                        }

                        if (addAttr && !attrDictionary.Contains(attrArray[idx].TypeId))
                        {
                            attrDictionary[attrArray[idx].TypeId] = attrArray[idx];
                        }
                    }

                    attrArray = new Attribute[attrDictionary.Count];
                    attrDictionary.Values.CopyTo(attrArray, 0);
                    _attributes = new AttributeCollection(attrArray);
                }

                return(_attributes);
            }
示例#7
0
            /// <summary>
            ///     Retrieves the editor for the given base type.
            /// </summary>
            internal object GetEditor(object instance, Type editorBaseType)
            {
                EditorAttribute typeAttr;

                // For instances, the design time object for them may want to redefine the
                // attributes.  So, we search the attribute here based on the instance.  If found,
                // we then search on the same attribute based on type.  If the two don't match, then
                // we cannot cache the value and must re-create every time.  It is rare for a designer
                // to override these attributes, so we want to be smart here.
                //
                if (instance != null)
                {
                    typeAttr = GetEditorAttribute(TypeDescriptor.GetAttributes(_type), editorBaseType);
                    EditorAttribute instanceAttr = GetEditorAttribute(TypeDescriptor.GetAttributes(instance), editorBaseType);
                    if (typeAttr != instanceAttr)
                    {
                        Type editorType = GetTypeFromName(instanceAttr.EditorTypeName);
                        if (editorType != null && editorBaseType.GetTypeInfo().IsAssignableFrom(editorType))
                        {
                            return(ReflectTypeDescriptionProvider.CreateInstance(editorType, _type));
                        }
                    }
                }

                // If we got here, we return our type-based editor.
                //
                lock (this)
                {
                    for (int idx = 0; idx < _editorCount; idx++)
                    {
                        if (_editorTypes[idx] == editorBaseType)
                        {
                            return(_editors[idx]);
                        }
                    }
                }

                // Editor is not cached yet.  Look in the attributes.
                //
                object editor = null;

                typeAttr = GetEditorAttribute(TypeDescriptor.GetAttributes(_type), editorBaseType);
                if (typeAttr != null)
                {
                    Type editorType = GetTypeFromName(typeAttr.EditorTypeName);
                    if (editorType != null && editorBaseType.GetTypeInfo().IsAssignableFrom(editorType))
                    {
                        editor = ReflectTypeDescriptionProvider.CreateInstance(editorType, _type);
                    }
                }

                // Editor is not in the attributes.  Search intrinsic tables.
                //
                if (editor == null)
                {
                    Hashtable intrinsicEditors = ReflectTypeDescriptionProvider.GetEditorTable(editorBaseType);
                    if (intrinsicEditors != null)
                    {
                        editor = ReflectTypeDescriptionProvider.SearchIntrinsicTable(intrinsicEditors, _type);
                    }

                    // As a quick sanity check, check to see that the editor we got back is of
                    // the correct type.
                    //
                    if (editor != null && !editorBaseType.GetTypeInfo().IsInstanceOfType(editor))
                    {
                        Debug.Fail($"Editor {editor.GetType().FullName} is not an instance of {editorBaseType.FullName} but it is in that base types table.");
                        editor = null;
                    }
                }

                if (editor != null)
                {
                    lock (this)
                    {
                        if (_editorTypes == null || _editorTypes.Length == _editorCount)
                        {
                            int newLength = (_editorTypes == null ? 4 : _editorTypes.Length * 2);

                            Type[]   newTypes   = new Type[newLength];
                            object[] newEditors = new object[newLength];

                            if (_editorTypes != null)
                            {
                                _editorTypes.CopyTo(newTypes, 0);
                                _editors.CopyTo(newEditors, 0);
                            }

                            _editorTypes = newTypes;
                            _editors     = newEditors;

                            _editorTypes[_editorCount] = editorBaseType;
                            _editors[_editorCount++]   = editor;
                        }
                    }
                }

                return(editor);
            }
示例#8
0
        protected override void FillAttributes(IList attributes)
        {
            foreach (Attribute attribute in TypeDescriptor.GetAttributes(this.PropertyType))
            {
                attributes.Add(attribute);
            }
            BindingFlags bindingAttr    = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;
            Type         componentClass = this.componentClass;
            int          num            = 0;

            while ((componentClass != null) && (componentClass != typeof(object)))
            {
                num++;
                componentClass = componentClass.BaseType;
            }
            if (num > 0)
            {
                componentClass = this.componentClass;
                Attribute[][] attributeArray = new Attribute[num][];
                while ((componentClass != null) && (componentClass != typeof(object)))
                {
                    MemberInfo member = null;
                    if (this.IsExtender)
                    {
                        member = componentClass.GetMethod("Get" + this.Name, bindingAttr);
                    }
                    else
                    {
                        member = componentClass.GetProperty(this.Name, bindingAttr, null, this.PropertyType, new Type[0], new ParameterModifier[0]);
                    }
                    if (member != null)
                    {
                        attributeArray[--num] = ReflectTypeDescriptionProvider.ReflectGetAttributes(member);
                    }
                    componentClass = componentClass.BaseType;
                }
                foreach (Attribute[] attributeArray2 in attributeArray)
                {
                    if (attributeArray2 != null)
                    {
                        foreach (Attribute attribute2 in attributeArray2)
                        {
                            AttributeProviderAttribute attribute3 = attribute2 as AttributeProviderAttribute;
                            if (attribute3 != null)
                            {
                                Type type = Type.GetType(attribute3.TypeName);
                                if (type != null)
                                {
                                    Attribute[] attributeArray3 = null;
                                    if (!string.IsNullOrEmpty(attribute3.PropertyName))
                                    {
                                        MemberInfo[] infoArray = type.GetMember(attribute3.PropertyName);
                                        if ((infoArray.Length > 0) && (infoArray[0] != null))
                                        {
                                            attributeArray3 = ReflectTypeDescriptionProvider.ReflectGetAttributes(infoArray[0]);
                                        }
                                    }
                                    else
                                    {
                                        attributeArray3 = ReflectTypeDescriptionProvider.ReflectGetAttributes((MemberInfo)type);
                                    }
                                    if (attributeArray3 != null)
                                    {
                                        foreach (Attribute attribute4 in attributeArray3)
                                        {
                                            attributes.Add(attribute4);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                foreach (Attribute[] attributeArray4 in attributeArray)
                {
                    if (attributeArray4 != null)
                    {
                        foreach (Attribute attribute5 in attributeArray4)
                        {
                            attributes.Add(attribute5);
                        }
                    }
                }
            }
            base.FillAttributes(attributes);
            if (this.SetMethodValue == null)
            {
                attributes.Add(ReadOnlyAttribute.Yes);
            }
        }
        /// <devdoc>
        ///      Searches the provided intrinsic hashtable for a match with the object type.
        ///      At the beginning, the hashtable contains types for the various converters.
        ///      As this table is searched, the types for these objects
        ///      are replaced with instances, so we only create as needed.  This method
        ///      does the search up the base class hierarchy and will create instances
        ///      for types as needed.  These instances are stored back into the table
        ///      for the base type, and for the original component type, for fast access.
        /// </devdoc>
        private static object SearchIntrinsicTable(Type callingType)
        {
            object hashEntry = null;

            // We take a lock on this table.  Nothing in this code calls out to
            // other methods that lock, so it should be fairly safe to grab this
            // lock.  Also, this allows multiple intrinsic tables to be searched
            // at once.
            //
            lock (ReflectTypeDescriptionProvider.s_syncObject)
            {
                Type baseType = callingType;
                while (baseType != null && baseType != typeof(object))
                {
                    if (ReflectTypeDescriptionProvider.IntrinsicTypeConverters.TryGetValue(baseType, out hashEntry) && hashEntry != null)
                    {
                        break;
                    }

                    baseType = baseType.GetTypeInfo().BaseType;
                }

                TypeInfo callingTypeInfo = callingType.GetTypeInfo();

                // Now make a scan through each value in the table, looking for interfaces.
                // If we find one, see if the object implements the interface.
                //
                if (hashEntry == null)
                {
                    foreach (object key in ReflectTypeDescriptionProvider.IntrinsicTypeConverters.Keys)
                    {
                        Type keyType = key as Type;

                        if (keyType != null)
                        {
                            TypeInfo keyTypeInfo = keyType.GetTypeInfo();
                            if (keyTypeInfo.IsInterface && keyTypeInfo.IsAssignableFrom(callingTypeInfo))
                            {
                                ReflectTypeDescriptionProvider.IntrinsicTypeConverters.TryGetValue(key, out hashEntry);
                                string converterTypeString = hashEntry as string;

                                if (converterTypeString != null)
                                {
                                    hashEntry = Type.GetType(converterTypeString);
                                    if (hashEntry != null)
                                    {
                                        ReflectTypeDescriptionProvider.IntrinsicTypeConverters[callingType] = hashEntry;
                                    }
                                }

                                if (hashEntry != null)
                                {
                                    break;
                                }
                            }
                        }
                    }
                }

                // Special case converter
                //
                if (hashEntry == null)
                {
                    if (callingTypeInfo.IsGenericType && callingTypeInfo.GetGenericTypeDefinition() == typeof(Nullable <>))
                    {
                        // Check if it is a nullable value
                        ReflectTypeDescriptionProvider.IntrinsicTypeConverters.TryGetValue(ReflectTypeDescriptionProvider.s_intrinsicNullableKey, out hashEntry);
                    }
                }

                // Interfaces do not derive from object, so we
                // must handle the case of no hash entry here.
                //
                if (hashEntry == null)
                {
                    ReflectTypeDescriptionProvider.IntrinsicTypeConverters.TryGetValue(typeof(object), out hashEntry);
                }

                // If the entry is a type, create an instance of it and then
                // replace the entry.  This way we only need to create once.
                // We can only do this if the object doesn't want a type
                // in its constructor.
                //
                Type type = hashEntry as Type;

                if (type != null)
                {
                    bool noTypeConstructor = true;
                    hashEntry = ReflectTypeDescriptionProvider.CreateInstance(type, callingType, ref noTypeConstructor);
                    if (noTypeConstructor)
                    {
                        ReflectTypeDescriptionProvider.IntrinsicTypeConverters[callingType] = hashEntry;
                    }
                }
            }
            return(hashEntry);
        }
        /// <devdoc>
        ///    Gets a type converter for the specified type.
        /// </devdoc>
        internal static TypeConverter GetConverter(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            // Obtaining attributes follows a very critical order: we must take care that
            // we merge attributes the right way.  Consider this:
            //
            // [A4]
            // interface IBase;
            //
            // [A3]
            // interface IDerived;
            //
            // [A2]
            // class Base : IBase;
            //
            // [A1]
            // class Derived : Base, IDerived
            //
            // We are retreving attributes in the following order:  A1 - A4.
            // Interfaces always lose to types, and interfaces and types
            // must be looked up in the same order.
            TypeConverterAttribute converterAttribute = ReflectTypeDescriptionProvider.GetTypeConverterAttributeIfAny(type);

            if (converterAttribute == null)
            {
                Type baseType = type.GetTypeInfo().BaseType;

                while (baseType != null && baseType != typeof(object))
                {
                    converterAttribute = ReflectTypeDescriptionProvider.GetTypeConverterAttributeIfAny(baseType);
                    if (converterAttribute != null)
                    {
                        break;
                    }
                    baseType = baseType.GetTypeInfo().BaseType;
                }
            }

            if (converterAttribute == null)
            {
                IEnumerable <Type> interfaces = type.GetTypeInfo().ImplementedInterfaces;
                foreach (Type iface in interfaces)
                {
                    // only do this for public interfaces.
                    //
                    if ((iface.GetTypeInfo().Attributes & (TypeAttributes.Public | TypeAttributes.NestedPublic)) != 0)
                    {
                        converterAttribute = GetTypeConverterAttributeIfAny(iface);
                        if (converterAttribute != null)
                        {
                            break;
                        }
                    }
                }
            }

            if (converterAttribute != null)
            {
                Type converterType = ReflectTypeDescriptionProvider.GetTypeFromName(converterAttribute.ConverterTypeName, type);
                if (converterType != null && typeof(TypeConverter).GetTypeInfo().IsAssignableFrom(converterType.GetTypeInfo()))
                {
                    bool noTypeConstructor = true;
                    return((TypeConverter)ReflectTypeDescriptionProvider.CreateInstance(converterType, type, ref noTypeConstructor));
                }
            }

            // We did not get a converter. Traverse up the base class chain until
            // we find one in the stock hashtable.
            //
            return((TypeConverter)ReflectTypeDescriptionProvider.SearchIntrinsicTable(type));
        }
        protected override void FillAttributes(IList attributes)
        {
            Debug.Assert(_componentClass != null, "Must have a component class for FillAttributes");

            //
            // The order that we fill in attributes is critical. The list of attributes will be
            // filtered so that matching attributes at the end of the list replace earlier matches
            // (last one in wins). Therefore, the four categories of attributes we add must be
            // added as follows:
            //
            // 1. Attributes of the property type. These are the lowest level and should be
            //     overwritten by any newer attributes.
            //
            // 2. Attributes obtained from any SpecificTypeAttribute. These supercede attributes
            //     for the property type.
            //
            // 3. Attributes of the property itself, from base class to most derived. This way
            //     derived class attributes replace base class attributes.
            //
            // 4. Attributes from our base MemberDescriptor. While this seems opposite of what
            //     we want, MemberDescriptor only has attributes if someone passed in a new
            //     set in the constructor. Therefore, these attributes always
            //     supercede existing values.
            //


            // We need to include attributes from the type of the property.
            foreach (Attribute typeAttr in TypeDescriptor.GetAttributes(PropertyType))
            {
                attributes.Add(typeAttr);
            }

            // NOTE : Must look at method OR property, to handle the case of Extender properties...
            //
            // Note : Because we are using BindingFlags.DeclaredOnly it is more effcient to re-acquire
            //      : the property info, rather than use the one we have cached. The one we have cached
            //      : may ave come from a base class, meaning we will request custom metadata for this
            //      : class twice.

            Type currentReflectType = _componentClass;
            int  depth = 0;

            // First, calculate the depth of the object hierarchy. We do this so we can do a single
            // object create for an array of attributes.
            while (currentReflectType != null && currentReflectType != typeof(object))
            {
                depth++;
                currentReflectType = currentReflectType.BaseType;
            }

            // Now build up an array in reverse order
            if (depth > 0)
            {
                currentReflectType = _componentClass;
                Attribute[][] attributeStack = new Attribute[depth][];

                while (currentReflectType != null && currentReflectType != typeof(object))
                {
                    MemberInfo memberInfo = null;

                    BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly;
                    // Fill in our member info so we can get at the custom attributes.
                    if (IsExtender)
                    {
                        //receiverType is used to avoid ambitiousness when there are overloads for the get method.
                        memberInfo = currentReflectType.GetMethod("Get" + Name, bindingFlags, binder: null, new Type[] { _receiverType }, modifiers: null);
                    }
                    else
                    {
                        memberInfo = currentReflectType.GetProperty(Name, bindingFlags, binder: null, PropertyType, Array.Empty <Type>(), Array.Empty <ParameterModifier>());
                    }

                    // Get custom attributes for the member info.
                    if (memberInfo != null)
                    {
                        attributeStack[--depth] = ReflectTypeDescriptionProvider.ReflectGetAttributes(memberInfo);
                    }

                    // Ready for the next loop iteration.
                    currentReflectType = currentReflectType.BaseType;
                }

                // Look in the attribute stack for AttributeProviders
                foreach (Attribute[] attributeArray in attributeStack)
                {
                    if (attributeArray != null)
                    {
                        foreach (Attribute attr in attributeArray)
                        {
                            if (attr is AttributeProviderAttribute sta)
                            {
                                Type specificType = Type.GetType(sta.TypeName);

                                if (specificType != null)
                                {
                                    Attribute[] stAttrs = null;

                                    if (!string.IsNullOrEmpty(sta.PropertyName))
                                    {
                                        MemberInfo[] milist = specificType.GetMember(sta.PropertyName);
                                        if (milist.Length > 0 && milist[0] != null)
                                        {
                                            stAttrs = ReflectTypeDescriptionProvider.ReflectGetAttributes(milist[0]);
                                        }
                                    }
                                    else
                                    {
                                        stAttrs = ReflectTypeDescriptionProvider.ReflectGetAttributes(specificType);
                                    }
                                    if (stAttrs != null)
                                    {
                                        foreach (Attribute stAttr in stAttrs)
                                        {
                                            attributes.Add(stAttr);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                // Now trawl the attribute stack so that we add attributes
                // from base class to most derived.
                foreach (Attribute[] attributeArray in attributeStack)
                {
                    if (attributeArray != null)
                    {
                        foreach (Attribute attr in attributeArray)
                        {
                            attributes.Add(attr);
                        }
                    }
                }
            }

            // Include the base attributes. These override all attributes on the actual
            // property, so we want to add them last.
            base.FillAttributes(attributes);

            // Finally, override any form of ReadOnlyAttribute.
            if (SetMethodValue == null)
            {
                attributes.Add(ReadOnlyAttribute.Yes);
            }
        }