From 88e06a7372ca67dc5309c0dd33020105a3ec3a93 Mon Sep 17 00:00:00 2001 From: JeremyCaney Date: Sun, 21 Mar 2021 13:38:59 -0700 Subject: [PATCH] Established `ItemConfiguration` based on `PropertyConfiguration` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `ItemConfiguration` serves the same purpose as the `PropertyConfiguration`, except that it is not specific to `PropertyInfo`, and will also work with e.g. `MethodInfo`, `ConstructorInfo`—and, notable for our purposes, `ParameterInfo` (which doesn't otherwise share a base `MemberInfo` class with the rest of these). This will help facilitate constructor mapping (#35) , which relies on mapping `ParameterInfo` objects instead of `PropertyInfo` objects. --- ...yConfiguration.cs => ItemConfiguration.cs} | 93 +++++++++---------- 1 file changed, 43 insertions(+), 50 deletions(-) rename OnTopic/Mapping/Internal/{PropertyConfiguration.cs => ItemConfiguration.cs} (88%) diff --git a/OnTopic/Mapping/Internal/PropertyConfiguration.cs b/OnTopic/Mapping/Internal/ItemConfiguration.cs similarity index 88% rename from OnTopic/Mapping/Internal/PropertyConfiguration.cs rename to OnTopic/Mapping/Internal/ItemConfiguration.cs index 9c936106..5f5a0bc8 100644 --- a/OnTopic/Mapping/Internal/PropertyConfiguration.cs +++ b/OnTopic/Mapping/Internal/ItemConfiguration.cs @@ -7,7 +7,6 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; -using System.ComponentModel.DataAnnotations; using System.Linq; using System.Reflection; using OnTopic.Collections.Specialized; @@ -17,15 +16,15 @@ namespace OnTopic.Mapping.Internal { /*============================================================================================================================ - | CLASS: PROPERTY ATTRIBUTES + | CLASS: ITEM CONFIGURATION \---------------------------------------------------------------------------------------------------------------------------*/ /// - /// Evaluates a instance for known , and exposes them through a set of - /// property values. + /// Evaluates the for a given instance for a or , and exposes known s through a set of property values. /// /// /// - /// The class is utilized by implementations of to + /// The class is utilized by implementations of to /// facilitate the mapping of source instances to Data Transfer Objects (DTOs), such as View Models. /// The attribute values provide hints to the mapping service that help manage how the mapping occurs. /// @@ -35,34 +34,42 @@ namespace OnTopic.Mapping.Internal { /// then the will instead use the value defined by that attribute, thus allowing a /// property on the DTO to be aliased to a different property or attribute name on the source . /// + /// + /// The works with both and + /// instances, whereas the works exclusively with instances. + /// /// - internal class PropertyConfiguration { + internal class ItemConfiguration { /*========================================================================================================================== | CONSTRUCTOR \-------------------------------------------------------------------------------------------------------------------------*/ /// - /// Given a instance, exposes a set of properties associated with known - /// instances. + /// Given an instance, exposes a set of properties associated with known instances. /// - /// The instance to check for values. + /// + /// The instance to check for values. + /// + /// The name of the or . /// The prefix to apply to the attributes. - internal PropertyConfiguration(PropertyInfo property, string? attributePrefix = "") { + internal ItemConfiguration(ICustomAttributeProvider source, string name, string? attributePrefix = "") { /*------------------------------------------------------------------------------------------------------------------------ | Validate parameters \-----------------------------------------------------------------------------------------------------------------------*/ - Contract.Requires(property, nameof(property)); + Contract.Requires(source, nameof(source)); + Contract.Requires(name, nameof(name)); /*------------------------------------------------------------------------------------------------------------------------ | Set backing property \-----------------------------------------------------------------------------------------------------------------------*/ - Property = property; + Source = source; /*------------------------------------------------------------------------------------------------------------------------ | Set default values \-----------------------------------------------------------------------------------------------------------------------*/ - AttributeKey = attributePrefix + property.Name; + AttributeKey = attributePrefix + name; AttributePrefix = attributePrefix; DefaultValue = null; InheritValue = false; @@ -77,23 +84,23 @@ internal PropertyConfiguration(PropertyInfo property, string? attributePrefix = /*------------------------------------------------------------------------------------------------------------------------ | Attributes: Retrieve basic attributes \-----------------------------------------------------------------------------------------------------------------------*/ - GetAttributeValue(property, a => MapAs = a.Type); - GetAttributeValue(property, a => DefaultValue = a.Value); - GetAttributeValue(property, a => InheritValue = true); - GetAttributeValue(property, a => AttributeKey = attributePrefix + a.Key); - GetAttributeValue(property, a => MapToParent = true); - GetAttributeValue(property, a => AttributePrefix += (a.AttributePrefix?? property.Name)); - GetAttributeValue(property, a => IncludeAssociations = a.Associations); - GetAttributeValue(property, a => FlattenChildren = true); - GetAttributeValue(property, a => MetadataKey = a.Key); - GetAttributeValue(property, a => DisableMapping = true); - GetAttributeValue(property, a => ContentTypeFilter = a.ContentType); + GetAttributeValue(source, a => MapAs = a.Type); + GetAttributeValue(source, a => DefaultValue = a.Value); + GetAttributeValue(source, a => InheritValue = true); + GetAttributeValue(source, a => AttributeKey = attributePrefix + a.Key); + GetAttributeValue(source, a => MapToParent = true); + GetAttributeValue(source, a => AttributePrefix += (a.AttributePrefix?? name)); + GetAttributeValue(source, a => IncludeAssociations = a.Associations); + GetAttributeValue(source, a => FlattenChildren = true); + GetAttributeValue(source, a => MetadataKey = a.Key); + GetAttributeValue(source, a => DisableMapping = true); + GetAttributeValue(source, a => ContentTypeFilter = a.ContentType); /*------------------------------------------------------------------------------------------------------------------------ | Attributes: Determine collection key and type \-----------------------------------------------------------------------------------------------------------------------*/ GetAttributeValue( - property, + source, a => { CollectionKey = a.Key ?? CollectionKey; CollectionType = a.Type; @@ -107,9 +114,9 @@ internal PropertyConfiguration(PropertyInfo property, string? attributePrefix = /*------------------------------------------------------------------------------------------------------------------------ | Attributes: Set attribute filters \-----------------------------------------------------------------------------------------------------------------------*/ - var filterByAttribute = property.GetCustomAttributes(true); - if (filterByAttribute is not null && filterByAttribute.Any()) { - foreach (var filter in filterByAttribute) { + var filterByAttributes = (FilterByAttributeAttribute[])source.GetCustomAttributes(typeof(FilterByAttributeAttribute), true); + if (filterByAttributes is not null && filterByAttributes.Any()) { + foreach (var filter in filterByAttributes) { AttributeFilters.Add(filter.Key, filter.Value); } } @@ -117,12 +124,12 @@ internal PropertyConfiguration(PropertyInfo property, string? attributePrefix = } /*========================================================================================================================== - | PROPERTY: PROPERTY + | PROPERTY: SOURCE \-------------------------------------------------------------------------------------------------------------------------*/ /// - /// The that the current is associated with. + /// The that the current is associated with. /// - internal PropertyInfo Property { get; } + internal ICustomAttributeProvider Source { get; } /*========================================================================================================================== | PROPERTY: ATTRIBUTE KEY @@ -441,20 +448,6 @@ internal bool SatisfiesAttributeFilters(Topic source) => source?.Attributes?.GetValue(f.Key, "")?.Equals(f.Value, StringComparison.OrdinalIgnoreCase)?? false ); - /*========================================================================================================================== - | METHOD: VALIDATE - \-------------------------------------------------------------------------------------------------------------------------*/ - /// - /// Given a target DTO, will automatically identify any attributes that derive from and - /// ensure that their conditions are satisfied. - /// - /// The target DTO to validate the current property on. - internal void Validate(object target) { - foreach (ValidationAttribute validator in Property.GetCustomAttributes(typeof(ValidationAttribute))) { - validator.Validate(Property.GetValue(target), Property.Name); - } - } - /*========================================================================================================================== | PRIVATE: GET ATTRIBUTE VALUE \-------------------------------------------------------------------------------------------------------------------------*/ @@ -463,12 +456,12 @@ internal void Validate(object target) { /// results. /// /// An type to evaluate. - /// The instance to pull the attribute from. + /// The instance to pull the attribute from. /// The to execute on the attribute. - private static void GetAttributeValue(PropertyInfo property, Action action) where T : Attribute { - var attribute = (T?)property.GetCustomAttribute(typeof(T), true); - if (attribute is not null) { - action(attribute); + private static void GetAttributeValue(ICustomAttributeProvider source, Action action) where T : Attribute { + var attributes = (T[])source.GetCustomAttributes(typeof(T), true); + if (attributes is not null) { + action(attributes.FirstOrDefault()); } }