This class wraps an PropertyDescriptor with something that looks like a property. It allows you to treat extended properties the same as regular properties.

Inheritance: PropertyDescriptor
 private static PropertyDescriptor[] ReflectGetExtendedProperties(IExtenderProvider provider)
 {
     PropertyDescriptor[] descriptorArray;
     IDictionary cache = TypeDescriptor.GetCache(provider);
     if (cache != null)
     {
         descriptorArray = cache[_extenderProviderPropertiesKey] as PropertyDescriptor[];
         if (descriptorArray != null)
         {
             return descriptorArray;
         }
     }
     if (_extendedPropertyCache == null)
     {
         lock (_internalSyncObject)
         {
             if (_extendedPropertyCache == null)
             {
                 _extendedPropertyCache = new Hashtable();
             }
         }
     }
     Type componentType = provider.GetType();
     ReflectPropertyDescriptor[] array = (ReflectPropertyDescriptor[]) _extendedPropertyCache[componentType];
     if (array == null)
     {
         lock (_internalSyncObject)
         {
             array = (ReflectPropertyDescriptor[]) _extendedPropertyCache[componentType];
             if (array == null)
             {
                 AttributeCollection attributes = TypeDescriptor.GetAttributes(componentType);
                 ArrayList list = new ArrayList(attributes.Count);
                 foreach (Attribute attribute in attributes)
                 {
                     ProvidePropertyAttribute attribute2 = attribute as ProvidePropertyAttribute;
                     if (attribute2 != null)
                     {
                         Type typeFromName = GetTypeFromName(attribute2.ReceiverTypeName);
                         if (typeFromName != null)
                         {
                             MethodInfo method = componentType.GetMethod("Get" + attribute2.PropertyName, new Type[] { typeFromName });
                             if (((method != null) && !method.IsStatic) && method.IsPublic)
                             {
                                 MethodInfo setMethod = componentType.GetMethod("Set" + attribute2.PropertyName, new Type[] { typeFromName, method.ReturnType });
                                 if ((setMethod != null) && (setMethod.IsStatic || !setMethod.IsPublic))
                                 {
                                     setMethod = null;
                                 }
                                 list.Add(new ReflectPropertyDescriptor(componentType, attribute2.PropertyName, method.ReturnType, typeFromName, method, setMethod, null));
                             }
                         }
                     }
                 }
                 array = new ReflectPropertyDescriptor[list.Count];
                 list.CopyTo(array, 0);
                 _extendedPropertyCache[componentType] = array;
             }
         }
     }
     descriptorArray = new PropertyDescriptor[array.Length];
     for (int i = 0; i < array.Length; i++)
     {
         Attribute[] attributeArray = null;
         IComponent component = provider as IComponent;
         if ((component == null) || (component.Site == null))
         {
             attributeArray = new Attribute[] { DesignOnlyAttribute.Yes };
         }
         ReflectPropertyDescriptor extenderInfo = array[i];
         descriptorArray[i] = new ExtendedPropertyDescriptor(extenderInfo, extenderInfo.ExtenderGetReceiverType(), provider, attributeArray);
     }
     if (cache != null)
     {
         cache[_extenderProviderPropertiesKey] = descriptorArray;
     }
     return descriptorArray;
 }
        /// <devdoc>
        ///     This performs the actual reflection needed to discover
        ///     extender properties.  If object caching is supported this
        ///     will maintain a cache of property descriptors on the
        ///     extender provider.  Extender properties are actually two
        ///     property descriptors in one.  There is a chunk of per-class
        ///     data in a ReflectPropertyDescriptor that defines the
        ///     parameter types and get and set methods of the extended property,
        ///     and there is an ExtendedPropertyDescriptor that combines this
        ///     with an extender provider object to create what looks like a
        ///     normal property.  ReflectGetExtendedProperties maintains two 
        ///     separate caches for these two sets:  a static one for the
        ///     ReflectPropertyDescriptor values that don't change for each
        ///     provider instance, and a per-provider cache that contains
        ///     the ExtendedPropertyDescriptors.
        /// </devdoc>
        private static PropertyDescriptor[] ReflectGetExtendedProperties(IExtenderProvider provider)
        {
            IDictionary cache = TypeDescriptor.GetCache(provider);
            PropertyDescriptor[] properties;

            if (cache != null)
            {
                properties = cache[_extenderProviderPropertiesKey] as PropertyDescriptor[];
                if (properties != null)
                {
                    return properties;
                }
            }

            // Our per-instance cache missed.  We have never seen this instance of the
            // extender provider before.  See if we can find our class-based
            // property store.
            //
            if (_extendedPropertyCache == null)
            {
                lock (_internalSyncObject)
                {
                    if (_extendedPropertyCache == null)
                    {
                        _extendedPropertyCache = new Hashtable();
                    }
                }
            }

            Type providerType = provider.GetType();
            ReflectPropertyDescriptor[] extendedProperties = (ReflectPropertyDescriptor[])_extendedPropertyCache[providerType];
            if (extendedProperties == null)
            {
                lock (_internalSyncObject)
                {
                    extendedProperties = (ReflectPropertyDescriptor[])_extendedPropertyCache[providerType];

                    // Our class-based property store failed as well, so we need to build up the set of
                    // extended properties here.
                    //
                    if (extendedProperties == null)
                    {
                        AttributeCollection attributes = TypeDescriptor.GetAttributes(providerType);
                        ArrayList extendedList = new ArrayList(attributes.Count);

                        foreach(Attribute attr in attributes) 
                        {
                            ProvidePropertyAttribute provideAttr = attr as ProvidePropertyAttribute;

                            if (provideAttr != null) 
                            {
                                Type receiverType = GetTypeFromName(provideAttr.ReceiverTypeName);

                                if (receiverType != null) 
                                {
                                    MethodInfo getMethod = providerType.GetMethod("Get" + provideAttr.PropertyName, new Type[] {receiverType});

                                    if (getMethod != null && !getMethod.IsStatic && getMethod.IsPublic) 
                                    {
                                        MethodInfo setMethod = providerType.GetMethod("Set" + provideAttr.PropertyName, new Type[] {receiverType, getMethod.ReturnType});

                                        if (setMethod != null && (setMethod.IsStatic || !setMethod.IsPublic)) 
                                        {
                                            setMethod = null;
                                        }

                                        extendedList.Add(new ReflectPropertyDescriptor(providerType, provideAttr.PropertyName, getMethod.ReturnType, receiverType, getMethod, setMethod, null));
                                    }
                                }
                            }
                        }

                        extendedProperties = new ReflectPropertyDescriptor[extendedList.Count];
                        extendedList.CopyTo(extendedProperties, 0);
                        _extendedPropertyCache[providerType] = extendedProperties;
                    }
                }
            }

            // Now that we have our extended properties we can build up a list of callable properties.  These can be 
            // returned to the user.
            //
            properties = new PropertyDescriptor[extendedProperties.Length];
            for (int idx = 0; idx < extendedProperties.Length; idx++)
            {
                Attribute[] attrs = null;
                IComponent comp = provider as IComponent;
                if (comp == null || comp.Site == null)
                {
                    attrs = new Attribute[] {DesignOnlyAttribute.Yes};
                }

                ReflectPropertyDescriptor  rpd = extendedProperties[idx];
                ExtendedPropertyDescriptor epd = new ExtendedPropertyDescriptor(rpd, rpd.ExtenderGetReceiverType(), provider, attrs);
                properties[idx] = epd;
            }

            if (cache != null)
            {
                cache[_extenderProviderPropertiesKey] = properties;
            }

            return properties;
        }