Skip to content

Commit f3a7b5a

Browse files
committed
[Core.Reflection] Modernize code
1 parent a495310 commit f3a7b5a

30 files changed

+2950
-3025
lines changed

sources/core/Stride.Core.Reflection/AttributeRegistry.cs

Lines changed: 89 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,123 +1,119 @@
11
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
22
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
3-
using System;
4-
using System.Collections.Generic;
5-
using System.Linq;
3+
64
using System.Reflection;
7-
using Stride.Core.Annotations;
85

9-
namespace Stride.Core.Reflection
6+
namespace Stride.Core.Reflection;
7+
8+
/// <summary>
9+
/// A default implementation for <see cref="IAttributeRegistry"/>.
10+
/// This implementation allows to retrieve default attributes for a member or
11+
/// to attach an attribute to a specific type/member.
12+
/// </summary>
13+
public class AttributeRegistry : IAttributeRegistry
1014
{
15+
private readonly object lockObject = new();
16+
private readonly Dictionary<MemberInfoKey, List<Attribute>> cachedAttributes = [];
17+
private readonly Dictionary<MemberInfo, List<Attribute>> registeredAttributes = [];
18+
19+
// TODO: move this in a different location
20+
public Action<ObjectDescriptor, List<IMemberDescriptor>>? PrepareMembersCallback { get; set; }
21+
1122
/// <summary>
12-
/// A default implementation for <see cref="IAttributeRegistry"/>.
13-
/// This implementation allows to retrieve default attributes for a member or
14-
/// to attach an attribute to a specific type/member.
23+
/// Gets the attributes associated with the specified member.
1524
/// </summary>
16-
public class AttributeRegistry : IAttributeRegistry
25+
/// <param name="memberInfo">The reflection member.</param>
26+
/// <param name="inherit">if set to <c>true</c> includes inherited attributes.</param>
27+
/// <returns>An enumeration of <see cref="Attribute"/>.</returns>
28+
public virtual List<Attribute> GetAttributes(MemberInfo memberInfo, bool inherit = true)
1729
{
18-
private readonly object lockObject = new();
19-
private readonly Dictionary<MemberInfoKey, List<Attribute>> cachedAttributes = [];
20-
private readonly Dictionary<MemberInfo, List<Attribute>> registeredAttributes = [];
21-
22-
// TODO: move this in a different location
23-
public Action<ObjectDescriptor, List<IMemberDescriptor>>? PrepareMembersCallback { get; set; }
24-
25-
/// <summary>
26-
/// Gets the attributes associated with the specified member.
27-
/// </summary>
28-
/// <param name="memberInfo">The reflection member.</param>
29-
/// <param name="inherit">if set to <c>true</c> includes inherited attributes.</param>
30-
/// <returns>An enumeration of <see cref="Attribute"/>.</returns>
31-
public virtual List<Attribute> GetAttributes(MemberInfo memberInfo, bool inherit = true)
30+
var key = new MemberInfoKey(memberInfo, inherit);
31+
32+
// Use a cache of attributes
33+
List<Attribute> attributes;
34+
lock (lockObject)
3235
{
33-
var key = new MemberInfoKey(memberInfo, inherit);
36+
if (cachedAttributes.TryGetValue(key, out var cacheAttributes))
37+
{
38+
return cacheAttributes;
39+
}
3440

35-
// Use a cache of attributes
36-
List<Attribute> attributes;
37-
lock (lockObject)
41+
// Else retrieve all default attributes
42+
var defaultAttributes = Attribute.GetCustomAttributes(memberInfo, inherit);
43+
IEnumerable<Attribute> attributesToCache = defaultAttributes;
44+
45+
// And add registered attributes
46+
if (registeredAttributes.TryGetValue(memberInfo, out var registered))
3847
{
39-
if (cachedAttributes.TryGetValue(key, out var cacheAttributes))
40-
{
41-
return cacheAttributes;
42-
}
43-
44-
// Else retrieve all default attributes
45-
var defaultAttributes = Attribute.GetCustomAttributes(memberInfo, inherit);
46-
IEnumerable<Attribute> attributesToCache = defaultAttributes;
47-
48-
// And add registered attributes
49-
if (registeredAttributes.TryGetValue(memberInfo, out var registered))
50-
{
51-
// Remove "real" attributes overridden by manually registered attributes
52-
attributesToCache = registered.Concat(defaultAttributes.Where(x => GetUsage(x).AllowMultiple || registered.All(y => y.GetType() != x.GetType())));
53-
}
54-
55-
attributes = attributesToCache.ToList();
56-
57-
// Add to the cache
58-
cachedAttributes.Add(key, attributes);
48+
// Remove "real" attributes overridden by manually registered attributes
49+
attributesToCache = registered.Concat(defaultAttributes.Where(x => GetUsage(x)!.AllowMultiple || registered.All(y => y.GetType() != x.GetType())));
5950
}
6051

61-
return attributes;
52+
attributes = attributesToCache.ToList();
53+
54+
// Add to the cache
55+
cachedAttributes.Add(key, attributes);
6256
}
6357

64-
/// <summary>
65-
/// Registers an attribute for the specified member. Restriction: Attributes registered this way cannot be listed in inherited attributes.
66-
/// </summary>
67-
/// <param name="memberInfo">The member information.</param>
68-
/// <param name="attribute">The attribute.</param>
69-
public void Register(MemberInfo memberInfo, Attribute attribute)
58+
return attributes;
59+
}
60+
61+
/// <summary>
62+
/// Registers an attribute for the specified member. Restriction: Attributes registered this way cannot be listed in inherited attributes.
63+
/// </summary>
64+
/// <param name="memberInfo">The member information.</param>
65+
/// <param name="attribute">The attribute.</param>
66+
public void Register(MemberInfo memberInfo, Attribute attribute)
67+
{
68+
lock (lockObject)
7069
{
71-
lock (lockObject)
70+
if (!registeredAttributes.TryGetValue(memberInfo, out var attributes))
7271
{
73-
if (!registeredAttributes.TryGetValue(memberInfo, out var attributes))
74-
{
75-
attributes = [];
76-
registeredAttributes.Add(memberInfo, attributes);
77-
}
78-
// Insert it in the first position to ensure it will override same attributes from base classes when using First
79-
attributes.Insert(0, attribute);
80-
81-
cachedAttributes.Remove(new MemberInfoKey(memberInfo, true));
82-
cachedAttributes.Remove(new MemberInfoKey(memberInfo, false));
72+
attributes = [];
73+
registeredAttributes.Add(memberInfo, attributes);
8374
}
84-
}
75+
// Insert it in the first position to ensure it will override same attributes from base classes when using First
76+
attributes.Insert(0, attribute);
8577

86-
private static AttributeUsageAttribute? GetUsage(Attribute attribute)
87-
{
88-
return Attribute.GetCustomAttribute(attribute.GetType(), typeof(AttributeUsageAttribute)) as AttributeUsageAttribute;
78+
cachedAttributes.Remove(new MemberInfoKey(memberInfo, true));
79+
cachedAttributes.Remove(new MemberInfoKey(memberInfo, false));
8980
}
81+
}
9082

91-
private readonly struct MemberInfoKey : IEquatable<MemberInfoKey>
92-
{
93-
private readonly MemberInfo memberInfo;
83+
private static AttributeUsageAttribute? GetUsage(Attribute attribute)
84+
{
85+
return Attribute.GetCustomAttribute(attribute.GetType(), typeof(AttributeUsageAttribute)) as AttributeUsageAttribute;
86+
}
9487

95-
private readonly bool inherit;
88+
private readonly struct MemberInfoKey : IEquatable<MemberInfoKey>
89+
{
90+
private readonly MemberInfo memberInfo;
9691

97-
public MemberInfoKey(MemberInfo memberInfo, bool inherit)
98-
{
99-
ArgumentNullException.ThrowIfNull(memberInfo);
100-
this.memberInfo = memberInfo;
101-
this.inherit = inherit;
102-
}
92+
private readonly bool inherit;
10393

104-
public bool Equals(MemberInfoKey other)
105-
{
106-
return memberInfo.Equals(other.memberInfo) && inherit.Equals(other.inherit);
107-
}
94+
public MemberInfoKey(MemberInfo memberInfo, bool inherit)
95+
{
96+
ArgumentNullException.ThrowIfNull(memberInfo);
97+
this.memberInfo = memberInfo;
98+
this.inherit = inherit;
99+
}
108100

109-
public override bool Equals(object? obj)
110-
{
111-
if (ReferenceEquals(null, obj)) return false;
112-
return obj is MemberInfoKey key && Equals(key);
113-
}
101+
public bool Equals(MemberInfoKey other)
102+
{
103+
return memberInfo.Equals(other.memberInfo) && inherit.Equals(other.inherit);
104+
}
114105

115-
public override int GetHashCode()
106+
public override bool Equals(object? obj)
107+
{
108+
if (ReferenceEquals(null, obj)) return false;
109+
return obj is MemberInfoKey key && Equals(key);
110+
}
111+
112+
public override int GetHashCode()
113+
{
114+
unchecked
116115
{
117-
unchecked
118-
{
119-
return (memberInfo.GetHashCode()*397) ^ inherit.GetHashCode();
120-
}
116+
return (memberInfo.GetHashCode()*397) ^ inherit.GetHashCode();
121117
}
122118
}
123119
}

sources/core/Stride.Core.Reflection/DefaultKeyComparer.cs

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,41 +18,37 @@
1818
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1919
// THE SOFTWARE.
2020

21-
using System;
22-
using System.Collections.Generic;
21+
namespace Stride.Core.Reflection;
2322

24-
namespace Stride.Core.Reflection
23+
public class DefaultKeyComparer : IComparer<object>
2524
{
26-
public class DefaultKeyComparer : IComparer<object>
25+
public int Compare(object? x, object? y)
2726
{
28-
public int Compare(object? x, object? y)
27+
if (x is IMemberDescriptor left && y is IMemberDescriptor right)
2928
{
30-
if (x is IMemberDescriptor left && y is IMemberDescriptor right)
29+
// If order is defined, first order by order
30+
if (left.Order.HasValue || right.Order.HasValue)
3131
{
32-
// If order is defined, first order by order
33-
if (left.Order.HasValue | right.Order.HasValue)
34-
{
35-
var leftOrder = left.Order ?? int.MaxValue;
36-
var rightOrder = right.Order ?? int.MaxValue;
37-
return leftOrder.CompareTo(rightOrder);
38-
}
39-
40-
// else order by name (dynamic members, etc...)
41-
return left.DefaultNameComparer.Compare(left.Name, right.Name);
32+
var leftOrder = left.Order ?? int.MaxValue;
33+
var rightOrder = right.Order ?? int.MaxValue;
34+
return leftOrder.CompareTo(rightOrder);
4235
}
4336

44-
if (x is string sx && y is string sy)
45-
{
46-
return string.CompareOrdinal(sx, sy);
47-
}
37+
// else order by name (dynamic members, etc...)
38+
return left.DefaultNameComparer.Compare(left.Name, right.Name);
39+
}
4840

49-
if (x is IComparable leftComparable)
50-
{
51-
return leftComparable.CompareTo(y);
52-
}
41+
if (x is string sx && y is string sy)
42+
{
43+
return string.CompareOrdinal(sx, sy);
44+
}
5345

54-
var rightComparable = y as IComparable;
55-
return rightComparable?.CompareTo(y) ?? 0;
46+
if (x is IComparable leftComparable)
47+
{
48+
return leftComparable.CompareTo(y);
5649
}
50+
51+
var rightComparable = y as IComparable;
52+
return rightComparable?.CompareTo(y) ?? 0;
5753
}
5854
}
Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,47 @@
11
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
22
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
3-
using System;
4-
using System.Collections.Generic;
53

6-
namespace Stride.Core.Reflection
4+
namespace Stride.Core.Reflection;
5+
6+
public class DefaultMemberComparer : IComparer<object>
77
{
8-
public class DefaultMemberComparer : IComparer<object>
8+
public int Compare(object? x, object? y)
99
{
10-
public int Compare(object? x, object? y)
10+
if (x is IMemberDescriptor left && y is IMemberDescriptor right)
1111
{
12-
if (x is IMemberDescriptor left && y is IMemberDescriptor right)
12+
// If order is defined, first order by order
13+
if (left.Order.HasValue || right.Order.HasValue)
1314
{
14-
// If order is defined, first order by order
15-
if (left.Order.HasValue | right.Order.HasValue)
16-
{
17-
var leftOrder = left.Order ?? int.MaxValue;
18-
var rightOrder = right.Order ?? int.MaxValue;
19-
return leftOrder.CompareTo(rightOrder);
20-
}
21-
22-
// try to order by class hierarchy + token (same as declaration order)
23-
var leftMember = left.MemberInfo;
24-
var rightMember = right.MemberInfo;
25-
if (leftMember != null || rightMember != null)
26-
{
27-
var comparison = leftMember.CompareMetadataTokenWith(rightMember);
28-
if (comparison != 0)
29-
return comparison;
30-
}
31-
32-
// else order by name (dynamic members, etc...)
33-
return left.DefaultNameComparer.Compare(left.Name, right.Name);
15+
var leftOrder = left.Order ?? int.MaxValue;
16+
var rightOrder = right.Order ?? int.MaxValue;
17+
return leftOrder.CompareTo(rightOrder);
3418
}
3519

36-
if (x is string sx && y is string sy)
20+
// try to order by class hierarchy + token (same as declaration order)
21+
var leftMember = left.MemberInfo;
22+
var rightMember = right.MemberInfo;
23+
if (leftMember != null || rightMember != null)
3724
{
38-
return string.CompareOrdinal(sx, sy);
25+
var comparison = leftMember.CompareMetadataTokenWith(rightMember);
26+
if (comparison != 0)
27+
return comparison;
3928
}
4029

41-
if (x is IComparable leftComparable)
42-
{
43-
return leftComparable.CompareTo(y);
44-
}
30+
// else order by name (dynamic members, etc...)
31+
return left.DefaultNameComparer.Compare(left.Name, right.Name);
32+
}
4533

46-
var rightComparable = y as IComparable;
47-
return rightComparable?.CompareTo(y) ?? 0;
34+
if (x is string sx && y is string sy)
35+
{
36+
return string.CompareOrdinal(sx, sy);
4837
}
38+
39+
if (x is IComparable leftComparable)
40+
{
41+
return leftComparable.CompareTo(y);
42+
}
43+
44+
var rightComparable = y as IComparable;
45+
return rightComparable?.CompareTo(y) ?? 0;
4946
}
5047
}

sources/core/Stride.Core.Reflection/DefaultNamingConvention.cs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,17 @@
1818
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1919
// THE SOFTWARE.
2020

21-
using System;
21+
namespace Stride.Core.Yaml.Serialization;
2222

23-
namespace Stride.Core.Yaml.Serialization
23+
/// <summary>
24+
/// A naming convention where all members are outputed as-is.
25+
/// </summary>
26+
public class DefaultNamingConvention : IMemberNamingConvention
2427
{
25-
/// <summary>
26-
/// A naming convention where all members are outputed as-is.
27-
/// </summary>
28-
public class DefaultNamingConvention : IMemberNamingConvention
29-
{
30-
public StringComparer Comparer { get { return StringComparer.Ordinal; } }
28+
public StringComparer Comparer { get { return StringComparer.Ordinal; } }
3129

32-
public string Convert(string name)
33-
{
34-
return name;
35-
}
30+
public string Convert(string name)
31+
{
32+
return name;
3633
}
37-
}
34+
}

0 commit comments

Comments
 (0)