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-aquire
// : 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.GetTypeInfo().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;
#if VERIFY_REFLECTION_CHANGE
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, null, new Type[] { _receiverType }, null);
}
else
{
memberInfo = currentReflectType.GetProperty(Name, bindingFlags, null, PropertyType, Array.Empty<Type>(), Array.Empty<ParameterModifier>());
}
#else
// 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.GetTypeInfo().GetMethod("Get" + Name, new Type[] { _receiverType }, null);
}
else
{
memberInfo = currentReflectType.GetTypeInfo().GetProperty(Name, PropertyType, Array.Empty<Type>(), Array.Empty<ParameterModifier>());
}
#endif
// 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;
}
// Look in the attribute stack for AttributeProviders
//
foreach (Attribute[] attributeArray in attributeStack)
{
if (attributeArray != null)
{
foreach (Attribute attr in attributeArray)
{
AttributeProviderAttribute sta = attr as AttributeProviderAttribute;
if (sta != null)
{
Type specificType = Type.GetType(sta.TypeName);
if (specificType != null)
{
Attribute[] stAttrs = null;
if (!String.IsNullOrEmpty(sta.PropertyName))
{
MemberInfo[] milist = specificType.GetTypeInfo().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);
}
}