This class wraps an PropertyDescriptor with something that looks like a property. It allows you to treat extended properties the same as regular properties.
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; }