Skip to content

Commit 9705824

Browse files
committed
Updated ItemConfiguration to operate off of List<Attribute>
Previously, the `ItemConfiguration` operated off of a `ICustomAttributeProvider`, which gave it access to `GetCustomAttributes()`. This necessitated it calling `GetCustomAttributes()` at least once per property per request. Worse, due to inefficiencies in the code, it actually called it repeatedly. In practice, however, these will never change per property—unlike other aspects of `ItemConfiguration` which are state dependent—and, thus, can be called from a cached source. With the new `CustomAttributes` property on `MemberAccessor` (4f587df) and the `PropertyConfiguration` class now operating off of a `MemberAccessor` instead of a `PropertyInfo`, we can easily relay a `List<Attribute>` to `ItemConfiguration` instead of simply a `ParameterInfo` or `PropertyInfo` (which both implement `ICustomAttributeProvider`). As part of this, I now set the `CustomAttributes` to a protected property of `PropertyConfiguration` for easy access to these values, so it doesn't need to be relayed internally, and can be accessed by derived classes (which will come in handy for a final optimization of `PropertyConfiguration`).
1 parent 825bb8b commit 9705824

3 files changed

Lines changed: 40 additions & 29 deletions

File tree

OnTopic/Mapping/Internal/ItemConfiguration.cs

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ namespace OnTopic.Mapping.Internal {
1515
| CLASS: ITEM CONFIGURATION
1616
\---------------------------------------------------------------------------------------------------------------------------*/
1717
/// <summary>
18-
/// Evaluates the <see cref="ICustomAttributeProvider"/> for a given instance for a <see cref="ParameterInfo"/> or <see cref
18+
/// Evaluates the <see cref="IEnumerable{Attribute}"/> of a given instance for a <see cref="ParameterInfo"/> or <see cref
1919
/// ="PropertyInfo"/>, and exposes known <see cref="Attribute"/>s through a set of property values.
2020
/// </summary>
2121
/// <remarks>
@@ -41,20 +41,21 @@ internal class ItemConfiguration {
4141
| CONSTRUCTOR
4242
\-------------------------------------------------------------------------------------------------------------------------*/
4343
/// <summary>
44-
/// Given an <see cref="ICustomAttributeProvider"/> instance, exposes a set of properties associated with known <see cref=
45-
/// "Attribute"/> instances.
44+
/// Given an <see cref="IEnumerable{Attribute}"/> instance, exposes a set of properties associated with known
45+
/// <see cref="Attribute"/> instances.
4646
/// </summary>
47-
/// <param name="source">
48-
/// The <see cref="ICustomAttributeProvider"/> instance to check for <see cref="Attribute"/> values.
47+
/// <param name="customAttributes">
48+
/// The <see cref="IEnumerable{Attribute}"/> instance to check for <see cref="Attribute"/> values.
4949
/// </param>
5050
/// <param name="name">The name of the <see cref="ParameterInfo"/> or <see cref="PropertyInfo"/>.</param>
5151
/// <param name="attributePrefix">The prefix to apply to the attributes.</param>
52-
internal ItemConfiguration(ICustomAttributeProvider source, string name, string? attributePrefix = "") {
52+
internal ItemConfiguration(IEnumerable<Attribute> customAttributes, string name, string? attributePrefix = "") {
5353

5454
/*------------------------------------------------------------------------------------------------------------------------
5555
| Set backing property
5656
\-----------------------------------------------------------------------------------------------------------------------*/
57-
Source = source;
57+
CustomAttributes = customAttributes;
58+
var source = customAttributes;
5859

5960
/*------------------------------------------------------------------------------------------------------------------------
6061
| Set default values
@@ -74,23 +75,22 @@ internal ItemConfiguration(ICustomAttributeProvider source, string name, string?
7475
/*------------------------------------------------------------------------------------------------------------------------
7576
| Attributes: Retrieve basic attributes
7677
\-----------------------------------------------------------------------------------------------------------------------*/
77-
GetAttributeValue<MapAsAttribute>(source, a => MapAs = a.Type);
78-
GetAttributeValue<DefaultValueAttribute>(source, a => DefaultValue = a.Value);
79-
GetAttributeValue<InheritAttribute>(source, a => InheritValue = true);
80-
GetAttributeValue<AttributeKeyAttribute>(source, a => AttributeKey = attributePrefix + a.Key);
81-
GetAttributeValue<MapToParentAttribute>(source, a => MapToParent = true);
82-
GetAttributeValue<MapToParentAttribute>(source, a => AttributePrefix += (a.AttributePrefix?? name));
83-
GetAttributeValue<IncludeAttribute>(source, a => IncludeAssociations = a.Associations);
84-
GetAttributeValue<FlattenAttribute>(source, a => FlattenChildren = true);
85-
GetAttributeValue<MetadataAttribute>(source, a => MetadataKey = a.Key);
86-
GetAttributeValue<DisableMappingAttribute>(source, a => DisableMapping = true);
87-
GetAttributeValue<FilterByContentTypeAttribute>(source, a => ContentTypeFilter = a.ContentType);
78+
GetAttributeValue<MapAsAttribute>( a => MapAs = a.Type);
79+
GetAttributeValue<DefaultValueAttribute>( a => DefaultValue = a.Value);
80+
GetAttributeValue<InheritAttribute>( a => InheritValue = true);
81+
GetAttributeValue<AttributeKeyAttribute>( a => AttributeKey = attributePrefix + a.Key);
82+
GetAttributeValue<MapToParentAttribute>( a => MapToParent = true);
83+
GetAttributeValue<MapToParentAttribute>( a => AttributePrefix += (a.AttributePrefix?? name));
84+
GetAttributeValue<IncludeAttribute>( a => IncludeAssociations = a.Associations);
85+
GetAttributeValue<FlattenAttribute>( a => FlattenChildren = true);
86+
GetAttributeValue<MetadataAttribute>( a => MetadataKey = a.Key);
87+
GetAttributeValue<DisableMappingAttribute>( a => DisableMapping = true);
88+
GetAttributeValue<FilterByContentTypeAttribute>( a => ContentTypeFilter = a.ContentType);
8889

8990
/*------------------------------------------------------------------------------------------------------------------------
9091
| Attributes: Determine collection key and type
9192
\-----------------------------------------------------------------------------------------------------------------------*/
9293
GetAttributeValue<CollectionAttribute>(
93-
source,
9494
a => {
9595
CollectionKey = a.Key ?? CollectionKey;
9696
CollectionType = a.Type;
@@ -104,7 +104,7 @@ internal ItemConfiguration(ICustomAttributeProvider source, string name, string?
104104
/*------------------------------------------------------------------------------------------------------------------------
105105
| Attributes: Set attribute filters
106106
\-----------------------------------------------------------------------------------------------------------------------*/
107-
var filterByAttributes = (FilterByAttributeAttribute[])source.GetCustomAttributes(typeof(FilterByAttributeAttribute), true);
107+
var filterByAttributes = source.OfType<FilterByAttributeAttribute>();
108108
if (filterByAttributes is not null && filterByAttributes.Any()) {
109109
foreach (var filter in filterByAttributes) {
110110
AttributeFilters.Add(filter.Key, filter.Value);
@@ -114,12 +114,12 @@ internal ItemConfiguration(ICustomAttributeProvider source, string name, string?
114114
}
115115

116116
/*==========================================================================================================================
117-
| PROPERTY: SOURCE
117+
| PROPERTY: CUSTOM ATTRIBUTES
118118
\-------------------------------------------------------------------------------------------------------------------------*/
119119
/// <summary>
120-
/// The <see cref="ICustomAttributeProvider"/> that the current <see cref="ItemConfiguration"/> is associated with.
120+
/// The <see cref="IEnumerable{Attribute}"/> that the current <see cref="ItemConfiguration"/> is associated with.
121121
/// </summary>
122-
internal ICustomAttributeProvider Source { get; }
122+
protected IEnumerable<Attribute> CustomAttributes { get; }
123123

124124
/*==========================================================================================================================
125125
| PROPERTY: ATTRIBUTE KEY
@@ -438,18 +438,28 @@ internal bool SatisfiesAttributeFilters(Topic source) =>
438438
source?.Attributes?.GetValue(f.Key, "")?.Equals(f.Value, StringComparison.OrdinalIgnoreCase)?? false
439439
);
440440

441+
/*==========================================================================================================================
442+
| PRIVATE: GET ATTRIBUTE
443+
\-------------------------------------------------------------------------------------------------------------------------*/
444+
/// <summary>
445+
/// Helper function identifies whether a <typeparamref name="T"/> exists in the <see cref="CustomAttributes"/> and, if so,
446+
/// returns the value.
447+
/// </summary>
448+
/// <typeparam name="T">An <see cref="Attribute"/> type to evaluate.</typeparam>
449+
private T? GetAttribute<T>() where T : Attribute =>
450+
CustomAttributes.OfType<T>().FirstOrDefault();
451+
441452
/*==========================================================================================================================
442453
| PRIVATE: GET ATTRIBUTE VALUE
443454
\-------------------------------------------------------------------------------------------------------------------------*/
444455
/// <summary>
445-
/// Helper function evaluates an attribute and then, if it exists, executes an <see cref="Action{T1}"/> to process the
456+
/// Helper function evaluates an attribute and then, if it exists, executes an <see cref="Action{T}"/> to process the
446457
/// results.
447458
/// </summary>
448459
/// <typeparam name="T">An <see cref="Attribute"/> type to evaluate.</typeparam>
449-
/// <param name="source">The <see cref="ICustomAttributeProvider"/> instance to pull the attribute from.</param>
450460
/// <param name="action">The <see cref="Action{T}"/> to execute on the attribute.</param>
451-
private static void GetAttributeValue<T>(ICustomAttributeProvider source, Action<T> action) where T : Attribute {
452-
var attribute = (T)source.GetCustomAttributes(typeof(T), true).FirstOrDefault();
461+
private void GetAttributeValue<T>(Action<T> action) where T : Attribute {
462+
var attribute = GetAttribute<T>();
453463
if (attribute is not null) {
454464
action(attribute);
455465
}

OnTopic/Mapping/Internal/PropertyConfiguration.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ internal class PropertyConfiguration: ItemConfiguration {
4444
/// </param>
4545
/// <param name="attributePrefix">The prefix to apply to the attributes.</param>
4646
internal PropertyConfiguration(MemberAccessor memberAccessor, string? attributePrefix = ""):
47-
base(memberAccessor, memberAccessor.Name, attributePrefix)
47+
base(memberAccessor.CustomAttributes, memberAccessor.Name, attributePrefix)
4848
{
4949
Property = (PropertyInfo)memberAccessor.MemberInfo;
5050
MemberAccessor = memberAccessor;

OnTopic/Mapping/TopicMappingService.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,8 @@ private async Task<object> MapAsync(
378378
/*------------------------------------------------------------------------------------------------------------------------
379379
| Establish per-property variables
380380
\-----------------------------------------------------------------------------------------------------------------------*/
381-
var configuration = new ItemConfiguration(parameter, parameter.Name, attributePrefix);
381+
var attributes = parameter.GetCustomAttributes(true).OfType<Attribute>();
382+
var configuration = new ItemConfiguration(attributes, parameter.Name, attributePrefix);
382383

383384
/*------------------------------------------------------------------------------------------------------------------------
384385
| Bypass if mapping is disabled

0 commit comments

Comments
 (0)