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;
}