Skip to content

Commit 71b0583

Browse files
committed
Optimization: avoid 2-level cache in AttributeHelper
1 parent f63b07a commit 71b0583

1 file changed

Lines changed: 54 additions & 72 deletions

File tree

Orm/Xtensive.Orm/Reflection/AttributeHelper.cs

Lines changed: 54 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@
1010
using System.Linq;
1111
using System.Reflection;
1212
using Xtensive.Core;
13-
using AttributesKey = System.ValueTuple<System.Reflection.MemberInfo, System.Type, Xtensive.Reflection.AttributeSearchOptions>;
1413
using PerAttributeKey = System.ValueTuple<System.Reflection.MemberInfo, Xtensive.Reflection.AttributeSearchOptions>;
15-
using Xtensive.Core;
1614

1715
namespace Xtensive.Reflection
1816
{
@@ -21,22 +19,63 @@ namespace Xtensive.Reflection
2119
/// </summary>
2220
public static class AttributeHelper
2321
{
24-
internal class AttributeExtractors<TAttribute> where TAttribute : Attribute
25-
{
26-
internal static readonly Func<PerAttributeKey, TAttribute[]> AttributesExtractor = key => {
27-
var uncasted = GetAttributes(key.Item1, typeof(TAttribute), key.Item2);
28-
return uncasted.Count > 0
29-
? uncasted.Cast<TAttribute>().ToArray(uncasted.Count)
30-
: Array.Empty<TAttribute>();
31-
};
32-
}
33-
3422
private static class AttributeDictionary<TAttribute> where TAttribute : Attribute
3523
{
24+
private static readonly Type attributeType = typeof(TAttribute);
3625
public static readonly ConcurrentDictionary<PerAttributeKey, TAttribute[]> Dictionary = new();
37-
}
3826

39-
private static readonly ConcurrentDictionary<AttributesKey, IReadOnlyList<Attribute>> AttributesByMemberInfoAndSearchOptions = new();
27+
private static List<TAttribute> GetAttributesAsNewList(MemberInfo member)
28+
{
29+
var attrObjects = member.GetCustomAttributes(attributeType, false);
30+
var attrs = new List<TAttribute>(attrObjects.Length);
31+
for (int i = 0, count = attrObjects.Length; i < count; ++i) {
32+
attrs.Add((TAttribute) attrObjects[i]);
33+
}
34+
return attrs;
35+
}
36+
37+
private static void AddAttributesFromBase(ref List<TAttribute> attributes, MemberInfo member, AttributeSearchOptions options)
38+
{
39+
if (member.GetBaseMember() is MemberInfo bm) {
40+
var attrsToAdd = bm.GetAttributes<TAttribute>(options);
41+
if (attrsToAdd.Count > 0) {
42+
(attributes ??= new List<TAttribute>(attrsToAdd.Count)).AddRange(attrsToAdd);
43+
}
44+
}
45+
}
46+
47+
public static readonly Func<PerAttributeKey, TAttribute[]> AttributesExtractor = key => {
48+
var (member, options) = key;
49+
50+
var attributesAsObjects = member.GetCustomAttributes(attributeType, false);
51+
var attributesCount = attributesAsObjects.Length;
52+
53+
var attributes = attributesCount > 0
54+
? attributesAsObjects.Cast<TAttribute>().ToList(attributesCount)
55+
: null;
56+
57+
if (options != AttributeSearchOptions.InheritNone) {
58+
if (attributesCount == 0) {
59+
if ((options & AttributeSearchOptions.InheritFromPropertyOrEvent) != 0
60+
&& member is MethodInfo m
61+
&& ((MemberInfo) m.GetProperty() ?? m.GetEvent()) is MemberInfo poe) {
62+
attributes = GetAttributesAsNewList(poe);
63+
}
64+
if ((options & AttributeSearchOptions.InheritFromBase) != 0
65+
&& (options & AttributeSearchOptions.InheritFromAllBase) == 0) {
66+
AddAttributesFromBase(ref attributes, member, options);
67+
}
68+
}
69+
70+
if ((options & AttributeSearchOptions.InheritFromAllBase) != 0
71+
&& member.DeclaringType != WellKnownTypes.Object) {
72+
AddAttributesFromBase(ref attributes, member, options);
73+
}
74+
}
75+
76+
return attributes?.ToArray(attributes.Count) ?? Array.Empty<TAttribute>();
77+
};
78+
}
4079

4180
/// <summary>
4281
/// A shortcut to <see cref="MemberInfo.GetCustomAttributes(Type,bool)"/> method.
@@ -48,7 +87,7 @@ private static class AttributeDictionary<TAttribute> where TAttribute : Attribut
4887
///
4988
public static IReadOnlyList<TAttribute> GetAttributes<TAttribute>(this MemberInfo member, AttributeSearchOptions options = AttributeSearchOptions.InheritNone)
5089
where TAttribute : Attribute =>
51-
AttributeDictionary<TAttribute>.Dictionary.GetOrAdd(new PerAttributeKey(member, options), AttributeExtractors<TAttribute>.AttributesExtractor);
90+
AttributeDictionary<TAttribute>.Dictionary.GetOrAdd(new PerAttributeKey(member, options), AttributeDictionary<TAttribute>.AttributesExtractor);
5291

5392
/// <summary>
5493
/// A version of <see cref="GetAttributes{TAttribute}(MemberInfo, AttributeSearchOptions)"/>
@@ -74,62 +113,5 @@ public static TAttribute GetAttribute<TAttribute>(this MemberInfo member, Attrib
74113
typeof(TAttribute).GetShortName()))
75114
};
76115
}
77-
78-
private static IReadOnlyList<Attribute> GetAttributes(MemberInfo member, Type attributeType, AttributeSearchOptions options) =>
79-
AttributesByMemberInfoAndSearchOptions.GetOrAdd(
80-
new AttributesKey(member, attributeType, options),
81-
ExtractAttributes
82-
);
83-
84-
private static List<Attribute> GetAttributesAsNewList(this MemberInfo member, Type attributeType)
85-
{
86-
var attrObjects = member.GetCustomAttributes(attributeType, false);
87-
var attrs = new List<Attribute>(attrObjects.Length);
88-
for (int i = 0, count = attrObjects.Length; i < count; ++i) {
89-
attrs.Add((Attribute) attrObjects[i]);
90-
}
91-
return attrs;
92-
}
93-
94-
private static IReadOnlyList<Attribute> ExtractAttributes((MemberInfo member, Type attributeType, AttributeSearchOptions options) t)
95-
{
96-
(var member, var attributeType, var options) = t;
97-
98-
var attributesAsObjects = member.GetCustomAttributes(attributeType, false);
99-
var attributesCount = attributesAsObjects.Length;
100-
101-
var attributes = attributesCount > 0
102-
? attributesAsObjects.Cast<Attribute>().ToList(attributesCount)
103-
: null;
104-
105-
if (options != AttributeSearchOptions.InheritNone) {
106-
if (attributesCount == 0) {
107-
if ((options & AttributeSearchOptions.InheritFromPropertyOrEvent) != 0
108-
&& member is MethodInfo m
109-
&& ((MemberInfo) m.GetProperty() ?? m.GetEvent()) is MemberInfo poe) {
110-
attributes = poe.GetAttributesAsNewList(attributeType);
111-
}
112-
if ((options & AttributeSearchOptions.InheritFromBase) != 0
113-
&& (options & AttributeSearchOptions.InheritFromAllBase) == 0
114-
&& member.GetBaseMember() is MemberInfo bm) {
115-
var attrsToAdd = GetAttributes(bm, attributeType, options);
116-
if (attrsToAdd.Count > 0) {
117-
(attributes ??= new List<Attribute>(attrsToAdd.Count)).AddRange(attrsToAdd);
118-
}
119-
}
120-
}
121-
122-
if ((options & AttributeSearchOptions.InheritFromAllBase) != 0
123-
&& member.DeclaringType != WellKnownTypes.Object
124-
&& member.GetBaseMember() is MemberInfo bm2) {
125-
var attrsToAdd = GetAttributes(bm2, attributeType, options);
126-
if (attrsToAdd.Count > 0) {
127-
(attributes ??= new List<Attribute>(attrsToAdd.Count)).AddRange(attrsToAdd);
128-
}
129-
}
130-
}
131-
132-
return (IReadOnlyList<Attribute>) attributes ?? Array.Empty<Attribute>();
133-
}
134116
}
135117
}

0 commit comments

Comments
 (0)