|
1 | | -// Copyright (C) 2008-2021 Xtensive LLC. |
| 1 | +// Copyright (C) 2008-2022 Xtensive LLC. |
2 | 2 | // This code is distributed under MIT license terms. |
3 | 3 | // See the License.txt file in the project root for more information. |
4 | 4 | // Created by: Alex Yakunin |
|
11 | 11 | using System.Reflection; |
12 | 12 | using AttributesKey = System.ValueTuple<System.Reflection.MemberInfo, System.Type, Xtensive.Reflection.AttributeSearchOptions>; |
13 | 13 | using PerAttributeKey = System.ValueTuple<System.Reflection.MemberInfo, Xtensive.Reflection.AttributeSearchOptions>; |
| 14 | +using Xtensive.Core; |
14 | 15 |
|
15 | 16 | namespace Xtensive.Reflection |
16 | 17 | { |
@@ -71,43 +72,60 @@ public static TAttribute GetAttribute<TAttribute>(this MemberInfo member, Attrib |
71 | 72 | private static IReadOnlyList<Attribute> GetAttributes(MemberInfo member, Type attributeType, AttributeSearchOptions options) => |
72 | 73 | attributesByMemberInfoAndSearchOptions.GetOrAdd( |
73 | 74 | new AttributesKey(member, attributeType, options), |
74 | | - t => ExtractAttributes(t).ToArray() |
| 75 | + t => ExtractAttributes(t, out var count).ToArray(count) |
75 | 76 | ); |
76 | 77 |
|
77 | | - private static Attribute[] GetAttributes(this MemberInfo member, Type attributeType) |
| 78 | + private static IEnumerable<Attribute> GetAttributes(this MemberInfo member, Type attributeType, out int count) |
78 | 79 | { |
79 | 80 | var attrObjects = member.GetCustomAttributes(attributeType, false); |
80 | | - var attrs = new Attribute[attrObjects.Length]; |
81 | | - for (int i = attrObjects.Length; i-- > 0;) { |
82 | | - attrs[i] = (Attribute) attrObjects[i]; |
83 | | - } |
84 | | - return attrs; |
| 81 | + count = attrObjects.Length; |
| 82 | + return (count == 0) |
| 83 | + ? Array.Empty<Attribute>() |
| 84 | + : attrObjects.Cast<Attribute>(); |
85 | 85 | } |
86 | 86 |
|
87 | | - private static IEnumerable<Attribute> ExtractAttributes((MemberInfo member, Type attributeType, AttributeSearchOptions options) t) { |
| 87 | + private static IEnumerable<Attribute> ExtractAttributes((MemberInfo member, Type attributeType, AttributeSearchOptions options) t, out int count) |
| 88 | + { |
88 | 89 | (var member, var attributeType, var options) = t; |
89 | 90 |
|
90 | | - var attributes = member.GetCustomAttributes(attributeType, false).Cast<Attribute>().ToList(); |
91 | | - if (options == AttributeSearchOptions.InheritNone) |
92 | | - return attributes; |
93 | | - if (attributes.Count == 0) { |
| 91 | + var customAttributesRaw = member.GetCustomAttributes(attributeType, false); |
| 92 | + count = customAttributesRaw.Length; |
| 93 | + |
| 94 | + if (options == AttributeSearchOptions.InheritNone) { |
| 95 | + return (customAttributesRaw.Length == 0) |
| 96 | + ? Array.Empty<Attribute>() |
| 97 | + : customAttributesRaw.Cast<Attribute>(); |
| 98 | + } |
| 99 | + |
| 100 | + IEnumerable<Attribute> attributes; |
| 101 | + if (customAttributesRaw.Length == 0) { |
| 102 | + attributes = Enumerable.Empty<Attribute>(); |
94 | 103 | if ((options & AttributeSearchOptions.InheritFromPropertyOrEvent) != 0 |
95 | 104 | && member is MethodInfo m |
96 | 105 | && ((MemberInfo) m.GetProperty() ?? m.GetEvent()) is MemberInfo poe) { |
97 | | - attributes = poe.GetAttributes(attributeType).ToList(); |
| 106 | + var poeAttributes = poe.GetAttributes(attributeType, out var count1); |
| 107 | + count = count1; |
| 108 | + attributes = poeAttributes; |
98 | 109 | } |
99 | 110 | if ((options & AttributeSearchOptions.InheritFromBase) != 0 |
100 | 111 | && (options & AttributeSearchOptions.InheritRecursively) == 0 |
101 | 112 | && member.GetBaseMember() is MemberInfo bm) { |
102 | | - attributes.AddRange(GetAttributes(bm, attributeType, options)); |
| 113 | + var inheritedAttributes = GetAttributes(bm, attributeType, options); |
| 114 | + count += inheritedAttributes.Count; |
| 115 | + attributes = attributes.Concat(inheritedAttributes); |
103 | 116 | return attributes; |
104 | 117 | } |
105 | 118 | } |
| 119 | + else { |
| 120 | + attributes = customAttributesRaw.Cast<Attribute>(); |
| 121 | + } |
106 | 122 |
|
107 | 123 | if ((options & AttributeSearchOptions.InheritFromAllBase) == AttributeSearchOptions.InheritFromAllBase |
108 | 124 | && member.DeclaringType != WellKnownTypes.Object |
109 | 125 | && member.GetBaseMember() is MemberInfo bm2) { |
110 | | - attributes.AddRange(GetAttributes(bm2, attributeType, options)); |
| 126 | + var inheritedAttributes = GetAttributes(bm2, attributeType, options); |
| 127 | + count += inheritedAttributes.Count; |
| 128 | + attributes = attributes.Concat(inheritedAttributes); |
111 | 129 | } |
112 | 130 |
|
113 | 131 | return attributes; |
|
0 commit comments