1 // Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. 2 3 using System; 4 using System.Collections.Generic; 5 using System.ComponentModel; 6 using System.Linq; 7 8 namespace Microsoft.Web.Http.Data 9 { 10 /// <summary> 11 /// Extension methods for TypeDescriptors 12 /// </summary> 13 internal static class TypeDescriptorExtensions 14 { 15 /// <summary> 16 /// Extension method to extract only the explicitly specified attributes from a <see cref="PropertyDescriptor"/>. 17 /// </summary> 18 /// <remarks> 19 /// Normal TypeDescriptor semantics are to inherit the attributes of a property's type. This method 20 /// exists to suppress those inherited attributes. 21 /// </remarks> 22 /// <param name="propertyDescriptor">The property descriptor whose attributes are needed.</param> 23 /// <returns>A new <see cref="AttributeCollection"/> stripped of any attributes from the property's type.</returns> ExplicitAttributes(this PropertyDescriptor propertyDescriptor)24 public static AttributeCollection ExplicitAttributes(this PropertyDescriptor propertyDescriptor) 25 { 26 List<Attribute> attributes = new List<Attribute>(propertyDescriptor.Attributes.Cast<Attribute>()); 27 AttributeCollection typeAttributes = TypeDescriptor.GetAttributes(propertyDescriptor.PropertyType); 28 bool removedAttribute = false; 29 foreach (Attribute attr in typeAttributes) 30 { 31 for (int i = attributes.Count - 1; i >= 0; --i) 32 { 33 // We must use ReferenceEquals since attributes could Match if they are the same. 34 // Only ReferenceEquals will catch actual duplications. 35 if (Object.ReferenceEquals(attr, attributes[i])) 36 { 37 attributes.RemoveAt(i); 38 removedAttribute = true; 39 } 40 } 41 } 42 return removedAttribute ? new AttributeCollection(attributes.ToArray()) : propertyDescriptor.Attributes; 43 } 44 45 /// <summary> 46 /// Extension method to extract attributes from a type taking into account the inheritance type of attributes 47 /// </summary> 48 /// <remarks> 49 /// Normal TypeDescriptor semantics are to inherit the attributes of a type's base type, regardless of their 50 /// inheritance type. 51 /// </remarks> 52 /// <param name="type">The type whose attributes are needed.</param> 53 /// <returns>A new <see cref="AttributeCollection"/> stripped of any incorrectly inherited attributes from the type.</returns> Attributes(this Type type)54 public static AttributeCollection Attributes(this Type type) 55 { 56 AttributeCollection baseTypeAttributes = TypeDescriptor.GetAttributes(type.BaseType); 57 List<Attribute> typeAttributes = new List<Attribute>(TypeDescriptor.GetAttributes(type).Cast<Attribute>()); 58 foreach (Attribute attr in baseTypeAttributes) 59 { 60 AttributeUsageAttribute attributeUsageAtt = (AttributeUsageAttribute)TypeDescriptor.GetAttributes(attr)[typeof(AttributeUsageAttribute)]; 61 if (attributeUsageAtt != null && !attributeUsageAtt.Inherited) 62 { 63 for (int i = typeAttributes.Count - 1; i >= 0; --i) 64 { 65 // We must use ReferenceEquals since attributes could Match if they are the same. 66 // Only ReferenceEquals will catch actual duplications. 67 if (Object.ReferenceEquals(attr, typeAttributes[i])) 68 { 69 typeAttributes.RemoveAt(i); 70 break; 71 } 72 } 73 } 74 } 75 return new AttributeCollection(typeAttributes.ToArray()); 76 } 77 78 /// <summary> 79 /// Checks to see if an attribute collection contains any attributes of the provided type. 80 /// </summary> 81 /// <typeparam name="TAttribute">The attribute type to check for</typeparam> 82 /// <param name="attributes">The attribute collection to inspect</param> 83 /// <returns><c>True</c> if an attribute of the provided type is contained in the attribute collection.</returns> 84 public static bool ContainsAttributeType<TAttribute>(this AttributeCollection attributes) where TAttribute : Attribute 85 { 86 return attributes.Cast<Attribute>().Any(a => a.GetType() == typeof(TAttribute)); 87 } 88 } 89 } 90