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 three 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 of the property itself, from base class to most derived. This way
// derived class attributes replace base class attributes.
//
// 3. 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 DebugTypeDescriptor.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.
BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly;
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;
object[][] attributeStack = new object[depth][];
while(currentReflectType != null && currentReflectType != typeof(object)) {
MemberInfo memberInfo = null;
// Fill in our member info so we can get at the custom attributes.
//
if (IsExtender) {
memberInfo = currentReflectType.GetMethod("Get" + Name, bindingFlags);
}
else {
memberInfo = currentReflectType.GetProperty(Name, bindingFlags, null, PropertyType, new Type[0], new ParameterModifier[0]);
}
// Get custom attributes for the member info.
//
if (memberInfo != null) {
attributeStack[--depth] = DebugTypeDescriptor.GetCustomAttributes(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(object[] attributeArray in attributeStack) {
if (attributeArray != null) {
foreach(object attr in attributeArray) {
if (attr is Attribute) {
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 (!state[BitReadOnlyChecked]) {
state[BitReadOnlyChecked] = true;
if (SetMethodValue == null) {
attributes.Add(ReadOnlyAttribute.Yes);
}
}
}