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