From 31fbfb7cd66cbcadfdfd74881ecd9dfbaef4a58e Mon Sep 17 00:00:00 2001 From: Steve Wilkes Date: Thu, 22 Aug 2019 09:14:24 +0100 Subject: [PATCH 1/8] Reusing created variable value --- .../DataSources/Factories/MetaMemberDataSourcesFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AgileMapper/DataSources/Factories/MetaMemberDataSourcesFactory.cs b/AgileMapper/DataSources/Factories/MetaMemberDataSourcesFactory.cs index ca5df75a2..94d1d2824 100644 --- a/AgileMapper/DataSources/Factories/MetaMemberDataSourcesFactory.cs +++ b/AgileMapper/DataSources/Factories/MetaMemberDataSourcesFactory.cs @@ -235,7 +235,7 @@ private static bool TryGetMetaMember( return sm.IsEnumerable ? ObjectMappingDataFactory.ForElement(mappingData) - : ObjectMappingDataFactory.ForChild(sm, tm, 0, md); + : mappingData; }; break; From a5fce64de539722dd36efb44789ce1e0097fb467 Mon Sep 17 00:00:00 2001 From: Steve Wilkes Date: Thu, 22 Aug 2019 09:31:31 +0100 Subject: [PATCH 2/8] Switching single-method interfaces to delegates --- .../ConfiguredIgnoredSourceMember.cs | 3 ++ .../Factories/DataSourceFindContext.cs | 2 +- .../DefaultValueFallbackDataSourceFactory.cs | 4 +-- ...OrDefaultValueFallbackDataSourceFactory.cs | 4 +-- .../Factories/FallbackDataSourceFactory.cs | 6 ++++ .../Factories/IFallbackDataSourceFactory.cs | 9 ------ AgileMapper/MappingRuleSet.cs | 16 +++++----- AgileMapper/MappingRuleSetCollection.cs | 32 +++++++++---------- .../MemberMergePopulationGuardFactory.cs | 4 +-- .../Members/Population/MemberPopulator.cs | 2 +- .../NullMemberPopulationGuardFactory.cs | 4 +-- ...rdFactory.cs => PopulationGuardFactory.cs} | 5 +-- AgileMapper/Members/SourceMemberMatcher.cs | 4 +-- .../SourceDictionaryShortCircuitFactory.cs | 2 +- .../CopySourceEnumerablePopulationStrategy.cs | 4 +-- .../EnumerableMappingExpressionFactory.cs | 2 +- .../EnumerablePopulationStrategy.cs | 12 +++++++ .../IEnumerablePopulationStrategy.cs | 15 --------- .../MergeEnumerablePopulationStrategy.cs | 4 +-- .../OverwriteEnumerablePopulationStrategy.cs | 4 +-- ...ojectSourceEnumerablePopulationStrategy.cs | 4 +-- .../MapperKeys/DefaultRootMapperKeyFactory.cs | 13 ++++++++ .../MapperKeys/IRootMapperKeyFactory.cs | 7 ---- .../MapperKeys/RootMapperKeyFactory.cs | 11 +------ .../ObjectPopulation/ObjectMappingData.cs | 4 +-- .../IRepeatMappingStrategy.cs | 2 +- .../QueryProjectorMapperKeyFactory.cs | 4 +-- .../MapToDepthRepeatMappingStrategy.cs | 6 ++-- 28 files changed, 90 insertions(+), 99 deletions(-) create mode 100644 AgileMapper/DataSources/Factories/FallbackDataSourceFactory.cs delete mode 100644 AgileMapper/DataSources/Factories/IFallbackDataSourceFactory.cs rename AgileMapper/Members/Population/{IPopulationGuardFactory.cs => PopulationGuardFactory.cs} (53%) create mode 100644 AgileMapper/ObjectPopulation/Enumerables/EnumerablePopulationStrategy.cs delete mode 100644 AgileMapper/ObjectPopulation/Enumerables/IEnumerablePopulationStrategy.cs create mode 100644 AgileMapper/ObjectPopulation/MapperKeys/DefaultRootMapperKeyFactory.cs delete mode 100644 AgileMapper/ObjectPopulation/MapperKeys/IRootMapperKeyFactory.cs diff --git a/AgileMapper/Configuration/ConfiguredIgnoredSourceMember.cs b/AgileMapper/Configuration/ConfiguredIgnoredSourceMember.cs index 499a5207c..67245ae07 100644 --- a/AgileMapper/Configuration/ConfiguredIgnoredSourceMember.cs +++ b/AgileMapper/Configuration/ConfiguredIgnoredSourceMember.cs @@ -5,6 +5,9 @@ namespace AgileObjects.AgileMapper.Configuration using LinqExp = System.Linq.Expressions; #else using System.Linq.Expressions; +#endif +#if NET35 + using Extensions.Internal; #endif using Members; diff --git a/AgileMapper/DataSources/Factories/DataSourceFindContext.cs b/AgileMapper/DataSources/Factories/DataSourceFindContext.cs index a91b1fe49..6626a0716 100644 --- a/AgileMapper/DataSources/Factories/DataSourceFindContext.cs +++ b/AgileMapper/DataSources/Factories/DataSourceFindContext.cs @@ -42,7 +42,7 @@ private IList GetConfiguredDataSources(IMemberMapperData public IList ConfiguredDataSources { get; } public IDataSource GetFallbackDataSource() - => ChildMappingData.RuleSet.FallbackDataSourceFactory.Create(MapperData); + => ChildMappingData.RuleSet.FallbackDataSourceFactory.Invoke(MapperData); public IDataSource GetFinalDataSource(IDataSource foundDataSource) => GetFinalDataSource(foundDataSource, ChildMappingData); diff --git a/AgileMapper/DataSources/Factories/DefaultValueFallbackDataSourceFactory.cs b/AgileMapper/DataSources/Factories/DefaultValueFallbackDataSourceFactory.cs index 4f08cae79..24628c86e 100644 --- a/AgileMapper/DataSources/Factories/DefaultValueFallbackDataSourceFactory.cs +++ b/AgileMapper/DataSources/Factories/DefaultValueFallbackDataSourceFactory.cs @@ -2,9 +2,9 @@ namespace AgileObjects.AgileMapper.DataSources.Factories { using Members; - internal struct DefaultValueFallbackDataSourceFactory : IFallbackDataSourceFactory + internal static class DefaultValueFallbackDataSourceFactory { - public IDataSource Create(IMemberMapperData mapperData) + public static IDataSource Create(IMemberMapperData mapperData) => new DefaultValueFallbackDataSource(mapperData); private class DefaultValueFallbackDataSource : DataSourceBase diff --git a/AgileMapper/DataSources/Factories/ExistingOrDefaultValueFallbackDataSourceFactory.cs b/AgileMapper/DataSources/Factories/ExistingOrDefaultValueFallbackDataSourceFactory.cs index 38f5ed30c..42906afec 100644 --- a/AgileMapper/DataSources/Factories/ExistingOrDefaultValueFallbackDataSourceFactory.cs +++ b/AgileMapper/DataSources/Factories/ExistingOrDefaultValueFallbackDataSourceFactory.cs @@ -8,9 +8,9 @@ namespace AgileObjects.AgileMapper.DataSources.Factories using Members; using Members.Dictionaries; - internal struct ExistingOrDefaultValueFallbackDataSourceFactory : IFallbackDataSourceFactory + internal static class ExistingOrDefaultValueFallbackDataSourceFactory { - public IDataSource Create(IMemberMapperData mapperData) + public static IDataSource Create(IMemberMapperData mapperData) => new ExistingValueOrDefaultFallbackDataSource(mapperData); private class ExistingValueOrDefaultFallbackDataSource : DataSourceBase diff --git a/AgileMapper/DataSources/Factories/FallbackDataSourceFactory.cs b/AgileMapper/DataSources/Factories/FallbackDataSourceFactory.cs new file mode 100644 index 000000000..3834d7d1e --- /dev/null +++ b/AgileMapper/DataSources/Factories/FallbackDataSourceFactory.cs @@ -0,0 +1,6 @@ +namespace AgileObjects.AgileMapper.DataSources.Factories +{ + using Members; + + internal delegate IDataSource FallbackDataSourceFactory(IMemberMapperData mapperData); +} \ No newline at end of file diff --git a/AgileMapper/DataSources/Factories/IFallbackDataSourceFactory.cs b/AgileMapper/DataSources/Factories/IFallbackDataSourceFactory.cs deleted file mode 100644 index 0cd813e6b..000000000 --- a/AgileMapper/DataSources/Factories/IFallbackDataSourceFactory.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace AgileObjects.AgileMapper.DataSources.Factories -{ - using Members; - - internal interface IFallbackDataSourceFactory - { - IDataSource Create(IMemberMapperData mapperData); - } -} \ No newline at end of file diff --git a/AgileMapper/MappingRuleSet.cs b/AgileMapper/MappingRuleSet.cs index e8c4e7230..eda3bfb17 100644 --- a/AgileMapper/MappingRuleSet.cs +++ b/AgileMapper/MappingRuleSet.cs @@ -19,11 +19,11 @@ internal class MappingRuleSet public MappingRuleSet( string name, MappingRuleSetSettings settings, - IEnumerablePopulationStrategy enumerablePopulationStrategy, + EnumerablePopulationStrategy enumerablePopulationStrategy, IRepeatMappingStrategy repeatMappingStrategy, - IPopulationGuardFactory populationGuardFactory, - IFallbackDataSourceFactory fallbackDataSourceFactory, - IRootMapperKeyFactory rootMapperKeyFactory) + PopulationGuardFactory populationGuardFactory, + FallbackDataSourceFactory fallbackDataSourceFactory, + RootMapperKeyFactory rootMapperKeyFactory) : this(name) { Settings = settings; @@ -45,14 +45,14 @@ public MappingRuleSet(string name) public MappingRuleSetSettings Settings { get; } - public IEnumerablePopulationStrategy EnumerablePopulationStrategy { get; } + public EnumerablePopulationStrategy EnumerablePopulationStrategy { get; } public IRepeatMappingStrategy RepeatMappingStrategy { get; } - public IPopulationGuardFactory PopulationGuardFactory { get; } + public PopulationGuardFactory PopulationGuardFactory { get; } - public IFallbackDataSourceFactory FallbackDataSourceFactory { get; } + public FallbackDataSourceFactory FallbackDataSourceFactory { get; } - public IRootMapperKeyFactory RootMapperKeyFactory { get; } + public RootMapperKeyFactory RootMapperKeyFactory { get; } } } \ No newline at end of file diff --git a/AgileMapper/MappingRuleSetCollection.cs b/AgileMapper/MappingRuleSetCollection.cs index d61223f9e..ee1bcac25 100644 --- a/AgileMapper/MappingRuleSetCollection.cs +++ b/AgileMapper/MappingRuleSetCollection.cs @@ -17,20 +17,20 @@ internal class MappingRuleSetCollection private static readonly MappingRuleSet _createNew = new MappingRuleSet( Constants.CreateNew, MappingRuleSetSettings.ForInMemoryMapping(allowCloneEntityKeyMapping: true), - default(CopySourceEnumerablePopulationStrategy), + CopySourceEnumerablePopulationStrategy.Create, default(MapRepeatedCallRepeatMappingStrategy), - default(NullMemberPopulationGuardFactory), - default(ExistingOrDefaultValueFallbackDataSourceFactory), - default(RootMapperKeyFactory)); + NullMemberPopulationGuardFactory.Create, + ExistingOrDefaultValueFallbackDataSourceFactory.Create, + DefaultRootMapperKeyFactory.Create); private static readonly MappingRuleSet _overwrite = new MappingRuleSet( Constants.Overwrite, MappingRuleSetSettings.ForInMemoryMapping(rootHasPopulatedTarget: true), - default(OverwriteEnumerablePopulationStrategy), + OverwriteEnumerablePopulationStrategy.Create, default(MapRepeatedCallRepeatMappingStrategy), - default(NullMemberPopulationGuardFactory), - default(DefaultValueFallbackDataSourceFactory), - default(RootMapperKeyFactory)); + NullMemberPopulationGuardFactory.Create, + DefaultValueFallbackDataSourceFactory.Create, + DefaultRootMapperKeyFactory.Create); private static readonly MappingRuleSet _project = new MappingRuleSet( Constants.Project, @@ -45,20 +45,20 @@ internal class MappingRuleSetCollection ExpressionIsSupported = value => value.CanBeProjected(), AllowEnumerableAssignment = true }, - default(ProjectSourceEnumerablePopulationStrategy), + ProjectSourceEnumerablePopulationStrategy.Create, default(MapToDepthRepeatMappingStrategy), - default(NullMemberPopulationGuardFactory), - default(DefaultValueFallbackDataSourceFactory), - default(QueryProjectorMapperKeyFactory)); + NullMemberPopulationGuardFactory.Create, + DefaultValueFallbackDataSourceFactory.Create, + QueryProjectorMapperKeyFactory.Create); private static readonly MappingRuleSet _merge = new MappingRuleSet( Constants.Merge, MappingRuleSetSettings.ForInMemoryMapping(rootHasPopulatedTarget: true, allowGuardedBindings: false), - default(MergeEnumerablePopulationStrategy), + MergeEnumerablePopulationStrategy.Create, default(MapRepeatedCallRepeatMappingStrategy), - default(MemberMergePopulationGuardFactory), - default(ExistingOrDefaultValueFallbackDataSourceFactory), - default(RootMapperKeyFactory)); + MemberMergePopulationGuardFactory.Create, + ExistingOrDefaultValueFallbackDataSourceFactory.Create, + DefaultRootMapperKeyFactory.Create); public static readonly MappingRuleSetCollection Default = new MappingRuleSetCollection(_createNew, _overwrite, _project, _merge); diff --git a/AgileMapper/Members/Population/MemberMergePopulationGuardFactory.cs b/AgileMapper/Members/Population/MemberMergePopulationGuardFactory.cs index b021ee35d..936bd55d4 100644 --- a/AgileMapper/Members/Population/MemberMergePopulationGuardFactory.cs +++ b/AgileMapper/Members/Population/MemberMergePopulationGuardFactory.cs @@ -6,9 +6,9 @@ namespace AgileObjects.AgileMapper.Members.Population using System.Linq.Expressions; #endif - internal struct MemberMergePopulationGuardFactory : IPopulationGuardFactory + internal static class MemberMergePopulationGuardFactory { - public Expression GetPopulationGuard(IMemberPopulationContext context) + public static Expression Create(IMemberPopulationContext context) { var mapperData = context.MapperData; var populateCondition = context.PopulateCondition; diff --git a/AgileMapper/Members/Population/MemberPopulator.cs b/AgileMapper/Members/Population/MemberPopulator.cs index b56f92206..f2e6bfea7 100644 --- a/AgileMapper/Members/Population/MemberPopulator.cs +++ b/AgileMapper/Members/Population/MemberPopulator.cs @@ -93,7 +93,7 @@ public Expression GetPopulation() var populationGuard = MapperData .RuleSet .PopulationGuardFactory - .GetPopulationGuard(this); + .Invoke(this); var useSingleExpression = MapperData.UseMemberInitialisations(); diff --git a/AgileMapper/Members/Population/NullMemberPopulationGuardFactory.cs b/AgileMapper/Members/Population/NullMemberPopulationGuardFactory.cs index 09174c8ee..9e2d90273 100644 --- a/AgileMapper/Members/Population/NullMemberPopulationGuardFactory.cs +++ b/AgileMapper/Members/Population/NullMemberPopulationGuardFactory.cs @@ -6,9 +6,9 @@ namespace AgileObjects.AgileMapper.Members.Population using System.Linq.Expressions; #endif - internal struct NullMemberPopulationGuardFactory : IPopulationGuardFactory + internal static class NullMemberPopulationGuardFactory { - public Expression GetPopulationGuard(IMemberPopulationContext context) + public static Expression Create(IMemberPopulationContext context) => context.PopulateCondition; } } \ No newline at end of file diff --git a/AgileMapper/Members/Population/IPopulationGuardFactory.cs b/AgileMapper/Members/Population/PopulationGuardFactory.cs similarity index 53% rename from AgileMapper/Members/Population/IPopulationGuardFactory.cs rename to AgileMapper/Members/Population/PopulationGuardFactory.cs index d76c8ded5..effba39f8 100644 --- a/AgileMapper/Members/Population/IPopulationGuardFactory.cs +++ b/AgileMapper/Members/Population/PopulationGuardFactory.cs @@ -6,8 +6,5 @@ namespace AgileObjects.AgileMapper.Members.Population using System.Linq.Expressions; #endif - internal interface IPopulationGuardFactory - { - Expression GetPopulationGuard(IMemberPopulationContext context); - } + internal delegate Expression PopulationGuardFactory(IMemberPopulationContext context); } \ No newline at end of file diff --git a/AgileMapper/Members/SourceMemberMatcher.cs b/AgileMapper/Members/SourceMemberMatcher.cs index 10df438af..1e5302f34 100644 --- a/AgileMapper/Members/SourceMemberMatcher.cs +++ b/AgileMapper/Members/SourceMemberMatcher.cs @@ -20,7 +20,7 @@ public static SourceMemberMatch GetMatchFor( return SourceMemberMatch.Null; } - if (ExactMatchingMemberExists(parentSourceMember, targetMapperData, out var matchingMember) && + if (ExactMemberMatchExists(parentSourceMember, targetMapperData, out var matchingMember) && TypesAreCompatible(matchingMember.Type, targetMapperData)) { return new SourceMemberMatch(matchingMember, targetMappingData); @@ -46,7 +46,7 @@ public static SourceMemberMatch GetMatchFor( : SourceMemberMatch.Null; } - private static bool ExactMatchingMemberExists( + private static bool ExactMemberMatchExists( IQualifiedMember parentSourceMember, IMemberMapperData mapperData, out IQualifiedMember matchingMember) diff --git a/AgileMapper/ObjectPopulation/ComplexTypes/SourceDictionaryShortCircuitFactory.cs b/AgileMapper/ObjectPopulation/ComplexTypes/SourceDictionaryShortCircuitFactory.cs index eb0af0ebd..ba9114b4e 100644 --- a/AgileMapper/ObjectPopulation/ComplexTypes/SourceDictionaryShortCircuitFactory.cs +++ b/AgileMapper/ObjectPopulation/ComplexTypes/SourceDictionaryShortCircuitFactory.cs @@ -99,7 +99,7 @@ private static Expression GetFallbackValue(IObjectMappingData mappingData) return mappingData.MappingContext .RuleSet .FallbackDataSourceFactory - .Create(mappingData.MapperData) + .Invoke(mappingData.MapperData) .Value; } } diff --git a/AgileMapper/ObjectPopulation/Enumerables/CopySourceEnumerablePopulationStrategy.cs b/AgileMapper/ObjectPopulation/Enumerables/CopySourceEnumerablePopulationStrategy.cs index b527a8ad0..f2e2570a2 100644 --- a/AgileMapper/ObjectPopulation/Enumerables/CopySourceEnumerablePopulationStrategy.cs +++ b/AgileMapper/ObjectPopulation/Enumerables/CopySourceEnumerablePopulationStrategy.cs @@ -6,9 +6,9 @@ namespace AgileObjects.AgileMapper.ObjectPopulation.Enumerables using System.Linq.Expressions; #endif - internal struct CopySourceEnumerablePopulationStrategy : IEnumerablePopulationStrategy + internal static class CopySourceEnumerablePopulationStrategy { - public Expression GetPopulation(EnumerablePopulationBuilder builder, IObjectMappingData enumerableMappingData) + public static Expression Create(EnumerablePopulationBuilder builder, IObjectMappingData enumerableMappingData) { builder.AssignSourceVariableFromSourceObject(); builder.AssignTargetVariable(); diff --git a/AgileMapper/ObjectPopulation/Enumerables/EnumerableMappingExpressionFactory.cs b/AgileMapper/ObjectPopulation/Enumerables/EnumerableMappingExpressionFactory.cs index b4d324b86..e86d2172d 100644 --- a/AgileMapper/ObjectPopulation/Enumerables/EnumerableMappingExpressionFactory.cs +++ b/AgileMapper/ObjectPopulation/Enumerables/EnumerableMappingExpressionFactory.cs @@ -56,7 +56,7 @@ protected override IEnumerable GetObjectPopulation(MappingCreationCo yield break; } - yield return context.RuleSet.EnumerablePopulationStrategy.GetPopulation( + yield return context.RuleSet.EnumerablePopulationStrategy.Invoke( context.MapperData.EnumerablePopulationBuilder, context.MappingData); } diff --git a/AgileMapper/ObjectPopulation/Enumerables/EnumerablePopulationStrategy.cs b/AgileMapper/ObjectPopulation/Enumerables/EnumerablePopulationStrategy.cs new file mode 100644 index 000000000..bfc95600e --- /dev/null +++ b/AgileMapper/ObjectPopulation/Enumerables/EnumerablePopulationStrategy.cs @@ -0,0 +1,12 @@ +namespace AgileObjects.AgileMapper.ObjectPopulation.Enumerables +{ +#if NET35 + using Microsoft.Scripting.Ast; +#else + using System.Linq.Expressions; +#endif + + internal delegate Expression EnumerablePopulationStrategy( + EnumerablePopulationBuilder builder, + IObjectMappingData enumerableMappingData); +} diff --git a/AgileMapper/ObjectPopulation/Enumerables/IEnumerablePopulationStrategy.cs b/AgileMapper/ObjectPopulation/Enumerables/IEnumerablePopulationStrategy.cs deleted file mode 100644 index 18187c10c..000000000 --- a/AgileMapper/ObjectPopulation/Enumerables/IEnumerablePopulationStrategy.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace AgileObjects.AgileMapper.ObjectPopulation.Enumerables -{ -#if NET35 - using Microsoft.Scripting.Ast; -#else - using System.Linq.Expressions; -#endif - - internal interface IEnumerablePopulationStrategy - { - Expression GetPopulation( - EnumerablePopulationBuilder builder, - IObjectMappingData enumerableMappingData); - } -} diff --git a/AgileMapper/ObjectPopulation/Enumerables/MergeEnumerablePopulationStrategy.cs b/AgileMapper/ObjectPopulation/Enumerables/MergeEnumerablePopulationStrategy.cs index fd4a22833..ed0482bed 100644 --- a/AgileMapper/ObjectPopulation/Enumerables/MergeEnumerablePopulationStrategy.cs +++ b/AgileMapper/ObjectPopulation/Enumerables/MergeEnumerablePopulationStrategy.cs @@ -6,9 +6,9 @@ namespace AgileObjects.AgileMapper.ObjectPopulation.Enumerables using System.Linq.Expressions; #endif - internal struct MergeEnumerablePopulationStrategy : IEnumerablePopulationStrategy + internal static class MergeEnumerablePopulationStrategy { - public Expression GetPopulation( + public static Expression Create( EnumerablePopulationBuilder builder, IObjectMappingData enumerableMappingData) { diff --git a/AgileMapper/ObjectPopulation/Enumerables/OverwriteEnumerablePopulationStrategy.cs b/AgileMapper/ObjectPopulation/Enumerables/OverwriteEnumerablePopulationStrategy.cs index 5f8c43a72..389ad4c39 100644 --- a/AgileMapper/ObjectPopulation/Enumerables/OverwriteEnumerablePopulationStrategy.cs +++ b/AgileMapper/ObjectPopulation/Enumerables/OverwriteEnumerablePopulationStrategy.cs @@ -6,9 +6,9 @@ using System.Linq.Expressions; #endif - internal struct OverwriteEnumerablePopulationStrategy : IEnumerablePopulationStrategy + internal static class OverwriteEnumerablePopulationStrategy { - public Expression GetPopulation( + public static Expression Create( EnumerablePopulationBuilder builder, IObjectMappingData enumerableMappingData) { diff --git a/AgileMapper/ObjectPopulation/Enumerables/ProjectSourceEnumerablePopulationStrategy.cs b/AgileMapper/ObjectPopulation/Enumerables/ProjectSourceEnumerablePopulationStrategy.cs index 031aecd31..9a7fa2c0c 100644 --- a/AgileMapper/ObjectPopulation/Enumerables/ProjectSourceEnumerablePopulationStrategy.cs +++ b/AgileMapper/ObjectPopulation/Enumerables/ProjectSourceEnumerablePopulationStrategy.cs @@ -6,9 +6,9 @@ namespace AgileObjects.AgileMapper.ObjectPopulation.Enumerables using System.Linq.Expressions; #endif - internal struct ProjectSourceEnumerablePopulationStrategy : IEnumerablePopulationStrategy + internal static class ProjectSourceEnumerablePopulationStrategy { - public Expression GetPopulation( + public static Expression Create( EnumerablePopulationBuilder builder, IObjectMappingData enumerableMappingData) { diff --git a/AgileMapper/ObjectPopulation/MapperKeys/DefaultRootMapperKeyFactory.cs b/AgileMapper/ObjectPopulation/MapperKeys/DefaultRootMapperKeyFactory.cs new file mode 100644 index 000000000..5b1377236 --- /dev/null +++ b/AgileMapper/ObjectPopulation/MapperKeys/DefaultRootMapperKeyFactory.cs @@ -0,0 +1,13 @@ +namespace AgileObjects.AgileMapper.ObjectPopulation.MapperKeys +{ + internal static class DefaultRootMapperKeyFactory + { + public static ObjectMapperKeyBase Create(IObjectMappingData mappingData) + { + return new RootObjectMapperKey(mappingData.MappingTypes, mappingData.MappingContext) + { + MappingData = mappingData + }; + } + } +} \ No newline at end of file diff --git a/AgileMapper/ObjectPopulation/MapperKeys/IRootMapperKeyFactory.cs b/AgileMapper/ObjectPopulation/MapperKeys/IRootMapperKeyFactory.cs deleted file mode 100644 index 103174808..000000000 --- a/AgileMapper/ObjectPopulation/MapperKeys/IRootMapperKeyFactory.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace AgileObjects.AgileMapper.ObjectPopulation.MapperKeys -{ - internal interface IRootMapperKeyFactory - { - ObjectMapperKeyBase CreateRootKeyFor(IObjectMappingData mappingData); - } -} \ No newline at end of file diff --git a/AgileMapper/ObjectPopulation/MapperKeys/RootMapperKeyFactory.cs b/AgileMapper/ObjectPopulation/MapperKeys/RootMapperKeyFactory.cs index 18e778d77..dcd7e9730 100644 --- a/AgileMapper/ObjectPopulation/MapperKeys/RootMapperKeyFactory.cs +++ b/AgileMapper/ObjectPopulation/MapperKeys/RootMapperKeyFactory.cs @@ -1,13 +1,4 @@ namespace AgileObjects.AgileMapper.ObjectPopulation.MapperKeys { - internal struct RootMapperKeyFactory : IRootMapperKeyFactory - { - public ObjectMapperKeyBase CreateRootKeyFor(IObjectMappingData mappingData) - { - return new RootObjectMapperKey(mappingData.MappingTypes, mappingData.MappingContext) - { - MappingData = mappingData - }; - } - } + internal delegate ObjectMapperKeyBase RootMapperKeyFactory(IObjectMappingData mappingData); } \ No newline at end of file diff --git a/AgileMapper/ObjectPopulation/ObjectMappingData.cs b/AgileMapper/ObjectPopulation/ObjectMappingData.cs index 76fe8be37..c901ee6ff 100644 --- a/AgileMapper/ObjectPopulation/ObjectMappingData.cs +++ b/AgileMapper/ObjectPopulation/ObjectMappingData.cs @@ -83,7 +83,7 @@ private ObjectMappingData( public IRootMapperKey EnsureRootMapperKey() { - MapperKey = MappingContext.RuleSet.RootMapperKeyFactory.CreateRootKeyFor(this); + MapperKey = MappingContext.RuleSet.RootMapperKeyFactory.Invoke(this); return (IRootMapperKey)MapperKey; } @@ -373,7 +373,7 @@ public IObjectMappingData WithSource(IQualifiedMember newSourceMember) newSourceMappingData.MapperKey = MappingContext .RuleSet .RootMapperKeyFactory - .CreateRootKeyFor(newSourceMappingData); + .Invoke(newSourceMappingData); newSourceMappingData.MapperData.OriginalMapperData = MapperData; newSourceMappingData.MapperData.Context.IsForToTargetMapping = true; diff --git a/AgileMapper/ObjectPopulation/RepeatedMappings/IRepeatMappingStrategy.cs b/AgileMapper/ObjectPopulation/RepeatedMappings/IRepeatMappingStrategy.cs index d4fd514a3..f1ff14372 100644 --- a/AgileMapper/ObjectPopulation/RepeatedMappings/IRepeatMappingStrategy.cs +++ b/AgileMapper/ObjectPopulation/RepeatedMappings/IRepeatMappingStrategy.cs @@ -1,11 +1,11 @@ namespace AgileObjects.AgileMapper.ObjectPopulation.RepeatedMappings { - using Members; #if NET35 using Microsoft.Scripting.Ast; #else using System.Linq.Expressions; #endif + using Members; internal interface IRepeatMappingStrategy { diff --git a/AgileMapper/Queryables/QueryProjectorMapperKeyFactory.cs b/AgileMapper/Queryables/QueryProjectorMapperKeyFactory.cs index 379d7f444..21f2643e7 100644 --- a/AgileMapper/Queryables/QueryProjectorMapperKeyFactory.cs +++ b/AgileMapper/Queryables/QueryProjectorMapperKeyFactory.cs @@ -4,9 +4,9 @@ using ObjectPopulation; using ObjectPopulation.MapperKeys; - internal struct QueryProjectorMapperKeyFactory : IRootMapperKeyFactory + internal static class QueryProjectorMapperKeyFactory { - public ObjectMapperKeyBase CreateRootKeyFor(IObjectMappingData mappingData) + public static ObjectMapperKeyBase Create(IObjectMappingData mappingData) { var providerType = mappingData.GetSource().Provider.GetType(); diff --git a/AgileMapper/Queryables/Recursion/MapToDepthRepeatMappingStrategy.cs b/AgileMapper/Queryables/Recursion/MapToDepthRepeatMappingStrategy.cs index e76f3d6ef..73d60edac 100644 --- a/AgileMapper/Queryables/Recursion/MapToDepthRepeatMappingStrategy.cs +++ b/AgileMapper/Queryables/Recursion/MapToDepthRepeatMappingStrategy.cs @@ -1,13 +1,13 @@ namespace AgileObjects.AgileMapper.Queryables.Recursion { - using Members; - using ObjectPopulation; - using ObjectPopulation.RepeatedMappings; #if NET35 using Microsoft.Scripting.Ast; #else using System.Linq.Expressions; #endif + using Members; + using ObjectPopulation; + using ObjectPopulation.RepeatedMappings; internal struct MapToDepthRepeatMappingStrategy : IRepeatMappingStrategy { From 141954ae079f4dc7e847bde838052a3d5e70101d Mon Sep 17 00:00:00 2001 From: Steve Wilkes Date: Thu, 22 Aug 2019 10:32:42 +0100 Subject: [PATCH 3/8] Adding MemberPopulationContext --- .../WhenIgnoringSourceMembers.cs | 24 +++ .../ConfiguredIgnoredSourceMember.cs | 3 - .../Configuration/UserConfigurationSet.cs | 17 ++- .../Configuration/UserConfiguredItemBase.cs | 5 +- .../Members/Population/IMemberPopulator.cs | 2 + .../MemberMergePopulationGuardFactory.cs | 6 +- .../Members/Population/MemberPopulator.cs | 28 ++-- .../Population/MemberPopulatorFactory.cs | 139 ++++++++++-------- .../NullMemberPopulationGuardFactory.cs | 4 +- .../Population/PopulationGuardFactory.cs | 2 +- 10 files changed, 144 insertions(+), 86 deletions(-) diff --git a/AgileMapper.UnitTests/Configuration/WhenIgnoringSourceMembers.cs b/AgileMapper.UnitTests/Configuration/WhenIgnoringSourceMembers.cs index 68276685e..61217eddb 100644 --- a/AgileMapper.UnitTests/Configuration/WhenIgnoringSourceMembers.cs +++ b/AgileMapper.UnitTests/Configuration/WhenIgnoringSourceMembers.cs @@ -1,6 +1,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Configuration { using Common; + using TestClasses; #if !NET35 using Xunit; #else @@ -27,6 +28,29 @@ public void ShouldIgnoreAConfiguredSourceMember() } } + [Fact] + public void ShouldIgnoreAConfiguredSourceMemberConditionally() + { + using (var mapper = Mapper.CreateNew()) + { + mapper.WhenMapping + .From>() + .ToANew>() + .If(ctx => ctx.Source.Value < 5) + .IgnoreSource(pf => pf.Value); + + var matchingSource = new PublicField { Value = 3 }; + var matchingResult = mapper.Map(matchingSource).ToANew>(); + + matchingResult.Value.ShouldBeNull(); + + var nonMatchingSource = new PublicField { Value = 7 }; + var nonMatchingResult = mapper.Map(nonMatchingSource).ToANew>(); + + nonMatchingResult.Value.ShouldBe("7"); + } + } + #region Helper Classes private class IdTesterSource diff --git a/AgileMapper/Configuration/ConfiguredIgnoredSourceMember.cs b/AgileMapper/Configuration/ConfiguredIgnoredSourceMember.cs index 67245ae07..ee7896e0f 100644 --- a/AgileMapper/Configuration/ConfiguredIgnoredSourceMember.cs +++ b/AgileMapper/Configuration/ConfiguredIgnoredSourceMember.cs @@ -29,9 +29,6 @@ public ConfiguredIgnoredSourceMember(MappingConfigInfo configInfo, LambdaExpress throw new MappingConfigurationException(failureReason); } - public bool CouldApplyTo(IBasicMapperData mapperData) - => RuleSetMatches(mapperData) && TypesAreCompatible(mapperData); - public override bool AppliesTo(IBasicMapperData mapperData) { return base.AppliesTo(mapperData) && diff --git a/AgileMapper/Configuration/UserConfigurationSet.cs b/AgileMapper/Configuration/UserConfigurationSet.cs index 506371268..2eb8b8924 100644 --- a/AgileMapper/Configuration/UserConfigurationSet.cs +++ b/AgileMapper/Configuration/UserConfigurationSet.cs @@ -322,8 +322,21 @@ public void Add(ConfiguredIgnoredMember ignoredMember) IgnoredMembers.AddSortFilter(ignoredMember); } - public ConfiguredIgnoredMember GetMemberIgnoreOrNull(IBasicMapperData mapperData) - => _ignoredMembers.FindMatch(mapperData); + public IList GetMemberIgnoresFor(IBasicMapperData mapperData) + { + if (_ignoredMembers == null) + { + return Enumerable.EmptyArray; + } + + var ignoredMembers = _ignoredMembers + .Filter(im => im.CouldApplyTo(mapperData)) + .ToArray(); + + return ignoredMembers.Any() + ? ignoredMembers + : Enumerable.EmptyArray; + } #endregion diff --git a/AgileMapper/Configuration/UserConfiguredItemBase.cs b/AgileMapper/Configuration/UserConfiguredItemBase.cs index 22850bc52..5599a4e70 100644 --- a/AgileMapper/Configuration/UserConfiguredItemBase.cs +++ b/AgileMapper/Configuration/UserConfiguredItemBase.cs @@ -93,6 +93,9 @@ public Expression GetConditionOrNull(IMemberMapperData mapperData) protected virtual Expression GetConditionOrNull(IMemberMapperData mapperData, CallbackPosition position) => ConfigInfo.GetConditionOrNull(mapperData, position, TargetMember); + public bool CouldApplyTo(IBasicMapperData mapperData) + => RuleSetMatches(mapperData) && TypesMatch(mapperData); + public virtual bool AppliesTo(IBasicMapperData mapperData) { return RuleSetMatches(mapperData) && @@ -101,7 +104,7 @@ public virtual bool AppliesTo(IBasicMapperData mapperData) TypesMatch(mapperData); } - protected bool RuleSetMatches(IBasicMapperData mapperData) => ConfigInfo.IsFor(mapperData.RuleSet); + private bool RuleSetMatches(IBasicMapperData mapperData) => ConfigInfo.IsFor(mapperData.RuleSet); private bool TargetMembersMatch(IBasicMapperData mapperData) { diff --git a/AgileMapper/Members/Population/IMemberPopulator.cs b/AgileMapper/Members/Population/IMemberPopulator.cs index ff8c9146b..aed10148c 100644 --- a/AgileMapper/Members/Population/IMemberPopulator.cs +++ b/AgileMapper/Members/Population/IMemberPopulator.cs @@ -12,6 +12,8 @@ internal interface IMemberPopulator bool CanPopulate { get; } + Expression PopulateCondition { get; } + Expression GetPopulation(); } } \ No newline at end of file diff --git a/AgileMapper/Members/Population/MemberMergePopulationGuardFactory.cs b/AgileMapper/Members/Population/MemberMergePopulationGuardFactory.cs index 936bd55d4..a2e745b35 100644 --- a/AgileMapper/Members/Population/MemberMergePopulationGuardFactory.cs +++ b/AgileMapper/Members/Population/MemberMergePopulationGuardFactory.cs @@ -8,10 +8,10 @@ namespace AgileObjects.AgileMapper.Members.Population internal static class MemberMergePopulationGuardFactory { - public static Expression Create(IMemberPopulationContext context) + public static Expression Create(IMemberPopulator populator) { - var mapperData = context.MapperData; - var populateCondition = context.PopulateCondition; + var mapperData = populator.MapperData; + var populateCondition = populator.PopulateCondition; if (SkipPopulationGuarding(mapperData)) { diff --git a/AgileMapper/Members/Population/MemberPopulator.cs b/AgileMapper/Members/Population/MemberPopulator.cs index f2e6bfea7..0a14f5db7 100644 --- a/AgileMapper/Members/Population/MemberPopulator.cs +++ b/AgileMapper/Members/Population/MemberPopulator.cs @@ -7,12 +7,11 @@ namespace AgileObjects.AgileMapper.Members.Population #else using System.Linq.Expressions; #endif - using Configuration; using DataSources; using Extensions.Internal; using ReadableExpressions; - internal class MemberPopulator : IMemberPopulationContext, IMemberPopulator + internal class MemberPopulator : IMemberPopulator { private readonly DataSourceSet _dataSources; @@ -36,19 +35,20 @@ public static IMemberPopulator WithRegistration(DataSourceSet dataSources, Expre public static IMemberPopulator WithoutRegistration(DataSourceSet dataSources, Expression populateCondition = null) => new MemberPopulator(dataSources, populateCondition); - public static IMemberPopulator Unmappable(IMemberMapperData mapperData, string reason) - => CreateNullMemberPopulator(mapperData, targetMember => $"No way to populate {targetMember.Name} ({reason})"); + public static IMemberPopulator Unmappable(MemberPopulationContext context, string reason) + => CreateNullMemberPopulator(context, targetMember => $"No way to populate {targetMember.Name} ({reason})"); - public static IMemberPopulator IgnoredMember(IMemberMapperData mapperData, ConfiguredIgnoredMember configuredIgnore) - => CreateNullMemberPopulator(mapperData, configuredIgnore.GetIgnoreMessage); + public static IMemberPopulator IgnoredMember(MemberPopulationContext context) + => CreateNullMemberPopulator(context, context.MemberIgnore.GetIgnoreMessage); - public static IMemberPopulator NoDataSource(IMemberMapperData mapperData) + public static IMemberPopulator NoDataSource(MemberPopulationContext context) { - var noDataSources = CreateNullDataSourceSet(mapperData, GetNoDataSourceMessage); + var noDataSources = CreateNullDataSourceSet(context.MemberMapperData, GetNoDataSourceMessage); - mapperData.RegisterTargetMemberDataSourcesIfRequired(noDataSources); + context.MemberMapperData.RegisterTargetMemberDataSourcesIfRequired(noDataSources); - return new MemberPopulator(noDataSources); + return context.MappingContext.AddUnsuccessfulMemberPopulations + ? new MemberPopulator(noDataSources) : null; } private static string GetNoDataSourceMessage(QualifiedMember targetMember) @@ -59,10 +59,12 @@ private static string GetNoDataSourceMessage(QualifiedMember targetMember) } private static MemberPopulator CreateNullMemberPopulator( - IMemberMapperData mapperData, + MemberPopulationContext context, Func commentFactory) { - return new MemberPopulator(CreateNullDataSourceSet(mapperData, commentFactory)); + return context.AddUnsuccessfulMemberPopulations + ? new MemberPopulator(CreateNullDataSourceSet(context.MemberMapperData, commentFactory)) + : null; } private static DataSourceSet CreateNullDataSourceSet( @@ -179,7 +181,7 @@ private Expression GetPopulationWithVariables(Expression population) var populationBlock = (BlockExpression)population; return Expression.Block( - _dataSources.Variables.Append(populationBlock.Variables), + _dataSources.Variables.Append(populationBlock.Variables), populationBlock.Expressions); } diff --git a/AgileMapper/Members/Population/MemberPopulatorFactory.cs b/AgileMapper/Members/Population/MemberPopulatorFactory.cs index 03a788356..aa5861848 100644 --- a/AgileMapper/Members/Population/MemberPopulatorFactory.cs +++ b/AgileMapper/Members/Population/MemberPopulatorFactory.cs @@ -1,4 +1,4 @@ - namespace AgileObjects.AgileMapper.Members.Population +namespace AgileObjects.AgileMapper.Members.Population { using System; using System.Collections.Generic; @@ -14,6 +14,60 @@ namespace AgileObjects.AgileMapper.Members.Population using Members; using ObjectPopulation; + internal class MemberPopulationContext + { + private IList _memberIgnores; + private ConfiguredIgnoredMember _memberIgnore; + + public MemberPopulationContext(IObjectMappingData mappingData) + { + MappingData = mappingData; + } + + public MappingRuleSet RuleSet => MappingContext.RuleSet; + + public MapperContext MapperContext => MappingContext.MapperContext; + + private UserConfigurationSet UserConfigurations => MapperContext.UserConfigurations; + + public IMappingContext MappingContext => MappingData.MappingContext; + + public IObjectMappingData MappingData { get; } + + private ObjectMapperData MapperData => MappingData.MapperData; + + public IMemberMapperData MemberMapperData { get; private set; } + + public QualifiedMember TargetMember => MemberMapperData.TargetMember; + + public bool AddUnsuccessfulMemberPopulations => MappingContext.AddUnsuccessfulMemberPopulations; + + public MemberPopulationContext With(QualifiedMember targetMember) + { + MemberMapperData = new ChildMemberMapperData(targetMember, MapperData); + _memberIgnore = null; + return this; + } + + private IList MemberIgnores + => _memberIgnores ?? (_memberIgnores = UserConfigurations.GetMemberIgnoresFor(MemberMapperData)); + + public ConfiguredIgnoredMember MemberIgnore + => _memberIgnore ?? (_memberIgnore = MemberIgnores.FindMatch(MemberMapperData)); + + public bool TargetMemberIsUnconditionallyIgnored(out Expression populateCondition) + { + if (MemberIgnore == null) + { + populateCondition = null; + return false; + } + + populateCondition = _memberIgnore.GetConditionOrNull(MemberMapperData); + return (populateCondition == null); + } + } + internal class MemberPopulatorFactory { public static readonly MemberPopulatorFactory Default = new MemberPopulatorFactory(mapperData => @@ -31,108 +85,71 @@ public MemberPopulatorFactory(Func Create(IObjectMappingData mappingData) { + var populationContext = new MemberPopulationContext(mappingData); + return _targetMembersFactory .Invoke(mappingData.MapperData) - .Project(tm => - { - var memberPopulator = Create(tm, mappingData); - - if (memberPopulator.CanPopulate || - mappingData.MappingContext.AddUnsuccessfulMemberPopulations) - { - return memberPopulator; - } - - return null; - }) + .Project(tm => Create(populationContext.With(tm))) .WhereNotNull(); } - private static IMemberPopulator Create(QualifiedMember targetMember, IObjectMappingData mappingData) + private static IMemberPopulator Create(MemberPopulationContext context) { - var childMapperData = new ChildMemberMapperData(targetMember, mappingData.MapperData); - - if (TargetMemberIsUnmappable(childMapperData, mappingData, out var reason)) + if (TargetMemberIsUnmappable(context, out var reason)) { - return MemberPopulator.Unmappable(childMapperData, reason); + return MemberPopulator.Unmappable(context, reason); } - if (TargetMemberIsUnconditionallyIgnored( - childMapperData, - out var configuredIgnore, - out var populateCondition)) + if (context.TargetMemberIsUnconditionallyIgnored(out var populateCondition)) { - return MemberPopulator.IgnoredMember(childMapperData, configuredIgnore); + return MemberPopulator.IgnoredMember(context); } - var childMappingData = mappingData.GetChildMappingData(childMapperData); + var childMappingData = context.MappingData.GetChildMappingData(context.MemberMapperData); var dataSources = DataSourceSetFactory.CreateFor(childMappingData); if (dataSources.None) { - return MemberPopulator.NoDataSource(childMapperData); + return MemberPopulator.NoDataSource(context); } return MemberPopulator.WithRegistration(dataSources, populateCondition); } - private static bool TargetMemberIsUnmappable( - IMemberMapperData mapperData, - IObjectMappingData mappingData, - out string reason) + private static bool TargetMemberIsUnmappable(MemberPopulationContext context, out string reason) { - if (!mapperData.RuleSet.Settings.AllowSetMethods && - (mapperData.TargetMember.LeafMember.MemberType == MemberType.SetMethod)) + if (!context.RuleSet.Settings.AllowSetMethods && + (context.TargetMember.LeafMember.MemberType == MemberType.SetMethod)) { - reason = "Set methods are unsupported by rule set '" + mapperData.RuleSet.Name + "'"; + reason = "Set methods are unsupported by rule set '" + context.RuleSet.Name + "'"; return true; } - if (TargetMemberWillBePopulatedByCtor(mapperData, mappingData)) + if (TargetMemberWillBePopulatedByCtor(context)) { reason = "Expected to be populated by constructor parameter"; return true; } - return mapperData.TargetMemberIsUnmappable( - mapperData.TargetMember, + return context.MemberMapperData.TargetMemberIsUnmappable( + context.TargetMember, md => md.MapperContext.UserConfigurations.QueryDataSourceFactories(md), - mapperData.MapperContext.UserConfigurations, + context.MapperContext.UserConfigurations, out reason); } - private static bool TargetMemberWillBePopulatedByCtor(IMemberMapperData mapperData, IObjectMappingData mappingData) + private static bool TargetMemberWillBePopulatedByCtor(MemberPopulationContext context) { - if (!mapperData.TargetMember.LeafMember.HasMatchingCtorParameter || - (mapperData.RuleSet.Settings.RootHasPopulatedTarget && (mapperData.Parent?.IsRoot == true))) + if (!context.TargetMember.LeafMember.HasMatchingCtorParameter || + (context.RuleSet.Settings.RootHasPopulatedTarget && context.MappingData.IsRoot)) { return false; } - var creationInfos = mappingData.GetTargetObjectCreationInfos(); + var creationInfos = context.MappingData.GetTargetObjectCreationInfos(); return creationInfos.Any() && - creationInfos.All(ci => ci.IsUnconditional && ci.HasCtorParameterFor(mapperData.TargetMember.LeafMember)); - } - - private static bool TargetMemberIsUnconditionallyIgnored( - IMemberMapperData mapperData, - out ConfiguredIgnoredMember configuredIgnore, - out Expression populateCondition) - { - configuredIgnore = mapperData - .MapperContext - .UserConfigurations - .GetMemberIgnoreOrNull(mapperData); - - if (configuredIgnore == null) - { - populateCondition = null; - return false; - } - - populateCondition = configuredIgnore.GetConditionOrNull(mapperData); - return (populateCondition == null); + creationInfos.All(ci => ci.IsUnconditional && ci.HasCtorParameterFor(context.TargetMember.LeafMember)); } } } \ No newline at end of file diff --git a/AgileMapper/Members/Population/NullMemberPopulationGuardFactory.cs b/AgileMapper/Members/Population/NullMemberPopulationGuardFactory.cs index 9e2d90273..a9cb690b7 100644 --- a/AgileMapper/Members/Population/NullMemberPopulationGuardFactory.cs +++ b/AgileMapper/Members/Population/NullMemberPopulationGuardFactory.cs @@ -8,7 +8,7 @@ namespace AgileObjects.AgileMapper.Members.Population internal static class NullMemberPopulationGuardFactory { - public static Expression Create(IMemberPopulationContext context) - => context.PopulateCondition; + public static Expression Create(IMemberPopulator populator) + => populator.PopulateCondition; } } \ No newline at end of file diff --git a/AgileMapper/Members/Population/PopulationGuardFactory.cs b/AgileMapper/Members/Population/PopulationGuardFactory.cs index effba39f8..577ea8995 100644 --- a/AgileMapper/Members/Population/PopulationGuardFactory.cs +++ b/AgileMapper/Members/Population/PopulationGuardFactory.cs @@ -6,5 +6,5 @@ namespace AgileObjects.AgileMapper.Members.Population using System.Linq.Expressions; #endif - internal delegate Expression PopulationGuardFactory(IMemberPopulationContext context); + internal delegate Expression PopulationGuardFactory(IMemberPopulator populator); } \ No newline at end of file From 6e2c9f22b826612da4c3f193bd4751a1aefe0fc4 Mon Sep 17 00:00:00 2001 From: Steve Wilkes Date: Thu, 22 Aug 2019 10:51:15 +0100 Subject: [PATCH 4/8] Avoiding capture creation in .Project() --- .../CustomDataSourceTargetMemberSpecifier.cs | 17 +++-- .../MapperConfigurationSpecifier.cs | 2 +- AgileMapper/Api/PlanTargetSelector.cs | 2 +- .../Configuration/UserConfigurationSet.cs | 2 +- AgileMapper/Extensions/CollectionData.cs | 4 +- .../Extensions/PublicEnumerableExtensions.cs | 12 ++++ AgileMapper/Members/MemberCache.cs | 4 +- .../Members/MemberMapperDataExtensions.cs | 4 +- AgileMapper/Members/NamingSettings.cs | 2 +- .../Population/IMemberPopulationContext.cs | 15 ----- .../Population/MemberPopulationContext.cs | 65 +++++++++++++++++++ .../Population/MemberPopulatorFactory.cs | 62 +----------------- .../DictionaryMappingExpressionFactory.cs | 4 +- AgileMapper/TypeConversion/ToEnumConverter.cs | 4 +- .../TypeConversion/ToStringConverter.cs | 2 +- .../Validation/EnumMappingMismatchFinder.cs | 6 +- .../Validation/EnumMappingMismatchSet.cs | 2 +- AgileMapper/Validation/MappingValidator.cs | 1 - 18 files changed, 107 insertions(+), 103 deletions(-) delete mode 100644 AgileMapper/Members/Population/IMemberPopulationContext.cs create mode 100644 AgileMapper/Members/Population/MemberPopulationContext.cs diff --git a/AgileMapper/Api/Configuration/CustomDataSourceTargetMemberSpecifier.cs b/AgileMapper/Api/Configuration/CustomDataSourceTargetMemberSpecifier.cs index 1b2bae0e0..ead642388 100644 --- a/AgileMapper/Api/Configuration/CustomDataSourceTargetMemberSpecifier.cs +++ b/AgileMapper/Api/Configuration/CustomDataSourceTargetMemberSpecifier.cs @@ -276,19 +276,22 @@ private MappingConfigContinuation RegisterNamedContructorParam private static ParameterInfo GetUniqueConstructorParameterOrThrow(string name = null) { - var ignoreParameterType = typeof(TParam) == typeof(AnyParameterType); - var ignoreParameterName = name == null; + var settings = new + { + IgnoreParameterType = typeof(TParam) == typeof(AnyParameterType), + IgnoreParameterName = name == null + }; var matchingParameters = typeof(TTarget) .GetPublicInstanceConstructors() - .Project(ctor => new + .Project(settings, (s, ctor) => new { Ctor = ctor, MatchingParameters = ctor .GetParameters() .Filter(p => - (ignoreParameterType || (p.ParameterType == typeof(TParam))) && - (ignoreParameterName || (p.Name == name))) + (s.IgnoreParameterType || (p.ParameterType == typeof(TParam))) && + (s.IgnoreParameterName || (p.Name == name))) .ToArray() }) .Filter(d => d.MatchingParameters.Any()) @@ -296,14 +299,14 @@ private static ParameterInfo GetUniqueConstructorParameterOrThrow(string if (matchingParameters.Length == 0) { - throw MissingParameterException(GetParameterMatchInfo(name, !ignoreParameterType)); + throw MissingParameterException(GetParameterMatchInfo(name, !settings.IgnoreParameterType)); } var matchingParameterData = matchingParameters.First(); if (matchingParameterData.MatchingParameters.Length > 1) { - throw AmbiguousParameterException(GetParameterMatchInfo(name, !ignoreParameterType)); + throw AmbiguousParameterException(GetParameterMatchInfo(name, !settings.IgnoreParameterType)); } var matchingParameter = matchingParameterData.MatchingParameters.First(); diff --git a/AgileMapper/Api/Configuration/MapperConfigurationSpecifier.cs b/AgileMapper/Api/Configuration/MapperConfigurationSpecifier.cs index 43bef710f..2b2fca489 100644 --- a/AgileMapper/Api/Configuration/MapperConfigurationSpecifier.cs +++ b/AgileMapper/Api/Configuration/MapperConfigurationSpecifier.cs @@ -192,7 +192,7 @@ private MapperConfigurationSpecifier ApplyConfigurationsIn(IEnumerable con var orderedConfigurations = configurationIndexesByType .OrderBy(kvp => kvp.Value) - .Project(kvp => configurationDataByType[kvp.Key].Configuration); + .Project(configurationDataByType, (cdbt, kvp) => cdbt[kvp.Key].Configuration); Apply(orderedConfigurations); return this; diff --git a/AgileMapper/Api/PlanTargetSelector.cs b/AgileMapper/Api/PlanTargetSelector.cs index 4d493ee99..00f15fdd8 100644 --- a/AgileMapper/Api/PlanTargetSelector.cs +++ b/AgileMapper/Api/PlanTargetSelector.cs @@ -41,7 +41,7 @@ public MappingPlanSet To( .RuleSets .All .Filter(ruleSet => ruleSet != _mapperContext.RuleSets.Project) - .Project(rs => GetMappingPlan(rs, configurations)) + .Project(configurations, (cs, rs) => GetMappingPlan(rs, cs)) .ToArray()); } diff --git a/AgileMapper/Configuration/UserConfigurationSet.cs b/AgileMapper/Configuration/UserConfigurationSet.cs index 2eb8b8924..4fd103bc9 100644 --- a/AgileMapper/Configuration/UserConfigurationSet.cs +++ b/AgileMapper/Configuration/UserConfigurationSet.cs @@ -414,7 +414,7 @@ private static IList GetDataSources( IEnumerable factories, IMemberMapperData mapperData) { - return factories.Project(dsf => dsf.Create(mapperData)).ToArray(); + return factories.Project(mapperData, (md, dsf) => dsf.Create(md)).ToArray(); } public IEnumerable QueryDataSourceFactories(IBasicMapperData mapperData) diff --git a/AgileMapper/Extensions/CollectionData.cs b/AgileMapper/Extensions/CollectionData.cs index 427382ad3..6a1c876f4 100644 --- a/AgileMapper/Extensions/CollectionData.cs +++ b/AgileMapper/Extensions/CollectionData.cs @@ -114,9 +114,9 @@ private static Dictionary> GetItemsById(IEnumerable { return items .WhereNotNull() - .Project(item => new + .Project(idFactory, (f, item) => new { - Id = idFactory.Invoke(item), + Id = f.Invoke(item), Item = item }) .Filter(d => d.Id != null) diff --git a/AgileMapper/Extensions/PublicEnumerableExtensions.cs b/AgileMapper/Extensions/PublicEnumerableExtensions.cs index 33760728b..297b9bd5c 100644 --- a/AgileMapper/Extensions/PublicEnumerableExtensions.cs +++ b/AgileMapper/Extensions/PublicEnumerableExtensions.cs @@ -31,6 +31,18 @@ public static IEnumerable Project(this IEnumerable Project( + this IEnumerable items, + TArg argument, + Func projector) + { + foreach (var item in items) + { + yield return projector.Invoke(argument, item); + } + } + /// /// Project these to a new enumerable of type , /// using the given . diff --git a/AgileMapper/Members/MemberCache.cs b/AgileMapper/Members/MemberCache.cs index 8fa262dc9..2be10b356 100644 --- a/AgileMapper/Members/MemberCache.cs +++ b/AgileMapper/Members/MemberCache.cs @@ -58,9 +58,9 @@ public IList GetTargetMembers(Type targetType) var fieldsAndProperties = fields .Concat(properties) - .Project(m => + .Project(constructorParameterNames, (cpns, m) => { - m.HasMatchingCtorParameter = constructorParameterNames.Contains(m.Name, OrdinalIgnoreCase); + m.HasMatchingCtorParameter = cpns.Contains(m.Name, OrdinalIgnoreCase); return m; }) .ToArray(); diff --git a/AgileMapper/Members/MemberMapperDataExtensions.cs b/AgileMapper/Members/MemberMapperDataExtensions.cs index 4d08d9ef8..e0757c065 100644 --- a/AgileMapper/Members/MemberMapperDataExtensions.cs +++ b/AgileMapper/Members/MemberMapperDataExtensions.cs @@ -284,7 +284,7 @@ private static bool TargetMemberHasRecursiveObjectGraph(QualifiedMember targetMe var nonSimpleChildMembers = GetTargetMembers(mappingType) .Filter(m => !m.IsSimple) - .Project(cm => GetNonEnumerableChildMember(targetMember, cm)) + .Project(targetMember, GetNonEnumerableChildMember) .ToArray(); if (nonSimpleChildMembers.None()) @@ -327,7 +327,7 @@ private static bool TargetMemberEverRepeatsWithin(QualifiedMember parentMember, .ToArray(); if (sameTypedChildMembers - .Project(cm => GetNonEnumerableChildMember(parentMember, cm)) + .Project(parentMember, GetNonEnumerableChildMember) .Any(cm => cm != subjectMember)) { return true; diff --git a/AgileMapper/Members/NamingSettings.cs b/AgileMapper/Members/NamingSettings.cs index e7a271d8c..03fb37cee 100644 --- a/AgileMapper/Members/NamingSettings.cs +++ b/AgileMapper/Members/NamingSettings.cs @@ -195,7 +195,7 @@ private bool IsIdentifier(Member member) potentialIds.InsertRange(0, new[] { "Id", "Identifier" }); return _customNameMatchers - .Project(customNameMatcher => customNameMatcher.Match(member.Name)) + .Project(member, (m, customNameMatcher) => customNameMatcher.Match(m.Name)) .Any(memberNameMatch => memberNameMatch.Success && potentialIds.Contains(GetMemberName(memberNameMatch))); diff --git a/AgileMapper/Members/Population/IMemberPopulationContext.cs b/AgileMapper/Members/Population/IMemberPopulationContext.cs deleted file mode 100644 index de9ff6443..000000000 --- a/AgileMapper/Members/Population/IMemberPopulationContext.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace AgileObjects.AgileMapper.Members.Population -{ -#if NET35 - using Microsoft.Scripting.Ast; -#else - using System.Linq.Expressions; -#endif - - internal interface IMemberPopulationContext - { - IMemberMapperData MapperData { get; } - - Expression PopulateCondition { get; } - } -} \ No newline at end of file diff --git a/AgileMapper/Members/Population/MemberPopulationContext.cs b/AgileMapper/Members/Population/MemberPopulationContext.cs new file mode 100644 index 000000000..5c97a85fc --- /dev/null +++ b/AgileMapper/Members/Population/MemberPopulationContext.cs @@ -0,0 +1,65 @@ +namespace AgileObjects.AgileMapper.Members.Population +{ + using System.Collections.Generic; +#if NET35 + using Microsoft.Scripting.Ast; +#else + using System.Linq.Expressions; +#endif + using Configuration; + using ObjectPopulation; + + internal class MemberPopulationContext + { + private IList _memberIgnores; + private ConfiguredIgnoredMember _memberIgnore; + + public MemberPopulationContext(IObjectMappingData mappingData) + { + MappingData = mappingData; + } + + public MappingRuleSet RuleSet => MappingContext.RuleSet; + + public MapperContext MapperContext => MappingContext.MapperContext; + + private UserConfigurationSet UserConfigurations => MapperContext.UserConfigurations; + + public IMappingContext MappingContext => MappingData.MappingContext; + + public IObjectMappingData MappingData { get; } + + private ObjectMapperData MapperData => MappingData.MapperData; + + public IMemberMapperData MemberMapperData { get; private set; } + + public QualifiedMember TargetMember => MemberMapperData.TargetMember; + + public bool AddUnsuccessfulMemberPopulations => MappingContext.AddUnsuccessfulMemberPopulations; + + public MemberPopulationContext With(QualifiedMember targetMember) + { + MemberMapperData = new ChildMemberMapperData(targetMember, MapperData); + _memberIgnore = null; + return this; + } + + private IList MemberIgnores + => _memberIgnores ?? (_memberIgnores = UserConfigurations.GetMemberIgnoresFor(MemberMapperData)); + + public ConfiguredIgnoredMember MemberIgnore + => _memberIgnore ?? (_memberIgnore = MemberIgnores.FindMatch(MemberMapperData)); + + public bool TargetMemberIsUnconditionallyIgnored(out Expression populateCondition) + { + if (MemberIgnore == null) + { + populateCondition = null; + return false; + } + + populateCondition = _memberIgnore.GetConditionOrNull(MemberMapperData); + return (populateCondition == null); + } + } +} \ No newline at end of file diff --git a/AgileMapper/Members/Population/MemberPopulatorFactory.cs b/AgileMapper/Members/Population/MemberPopulatorFactory.cs index aa5861848..7e020a3fd 100644 --- a/AgileMapper/Members/Population/MemberPopulatorFactory.cs +++ b/AgileMapper/Members/Population/MemberPopulatorFactory.cs @@ -2,72 +2,12 @@ namespace AgileObjects.AgileMapper.Members.Population { using System; using System.Collections.Generic; -#if NET35 - using Microsoft.Scripting.Ast; -#else - using System.Linq.Expressions; -#endif - using Configuration; using DataSources.Factories; using Extensions; using Extensions.Internal; using Members; using ObjectPopulation; - internal class MemberPopulationContext - { - private IList _memberIgnores; - private ConfiguredIgnoredMember _memberIgnore; - - public MemberPopulationContext(IObjectMappingData mappingData) - { - MappingData = mappingData; - } - - public MappingRuleSet RuleSet => MappingContext.RuleSet; - - public MapperContext MapperContext => MappingContext.MapperContext; - - private UserConfigurationSet UserConfigurations => MapperContext.UserConfigurations; - - public IMappingContext MappingContext => MappingData.MappingContext; - - public IObjectMappingData MappingData { get; } - - private ObjectMapperData MapperData => MappingData.MapperData; - - public IMemberMapperData MemberMapperData { get; private set; } - - public QualifiedMember TargetMember => MemberMapperData.TargetMember; - - public bool AddUnsuccessfulMemberPopulations => MappingContext.AddUnsuccessfulMemberPopulations; - - public MemberPopulationContext With(QualifiedMember targetMember) - { - MemberMapperData = new ChildMemberMapperData(targetMember, MapperData); - _memberIgnore = null; - return this; - } - - private IList MemberIgnores - => _memberIgnores ?? (_memberIgnores = UserConfigurations.GetMemberIgnoresFor(MemberMapperData)); - - public ConfiguredIgnoredMember MemberIgnore - => _memberIgnore ?? (_memberIgnore = MemberIgnores.FindMatch(MemberMapperData)); - - public bool TargetMemberIsUnconditionallyIgnored(out Expression populateCondition) - { - if (MemberIgnore == null) - { - populateCondition = null; - return false; - } - - populateCondition = _memberIgnore.GetConditionOrNull(MemberMapperData); - return (populateCondition == null); - } - } - internal class MemberPopulatorFactory { public static readonly MemberPopulatorFactory Default = new MemberPopulatorFactory(mapperData => @@ -89,7 +29,7 @@ public IEnumerable Create(IObjectMappingData mappingData) return _targetMembersFactory .Invoke(mappingData.MapperData) - .Project(tm => Create(populationContext.With(tm))) + .Project(populationContext, (ctx, tm) => Create(ctx.With(tm))) .WhereNotNull(); } diff --git a/AgileMapper/ObjectPopulation/DictionaryMappingExpressionFactory.cs b/AgileMapper/ObjectPopulation/DictionaryMappingExpressionFactory.cs index 5a4df4d02..477b2a14f 100644 --- a/AgileMapper/ObjectPopulation/DictionaryMappingExpressionFactory.cs +++ b/AgileMapper/ObjectPopulation/DictionaryMappingExpressionFactory.cs @@ -211,11 +211,11 @@ private static QualifiedMember[] GetConfiguredTargetMembers( { return configuredDataSourceFactories .GroupBy(dsf => dsf.TargetDictionaryEntryMember.Name) - .Project(group => + .Project(targetMembersFromSource, (tmfs, group) => { QualifiedMember targetMember = group.First().TargetDictionaryEntryMember; - targetMember.IsCustom = targetMembersFromSource.None( + targetMember.IsCustom = tmfs.None( sourceMember => sourceMember.RegistrationName == targetMember.Name); return targetMember.IsCustom ? targetMember : null; diff --git a/AgileMapper/TypeConversion/ToEnumConverter.cs b/AgileMapper/TypeConversion/ToEnumConverter.cs index 08d1de9ce..a1436d284 100644 --- a/AgileMapper/TypeConversion/ToEnumConverter.cs +++ b/AgileMapper/TypeConversion/ToEnumConverter.cs @@ -394,10 +394,10 @@ private Expression GetEnumToEnumConversion( }); var enumPairsConversion = sourceEnumValues - .Project(sv => new + .Project(enumPairs, (eps, sv) => new { SourceValue = sv, - PairedValue = enumPairs[sv] + PairedValue = eps[sv] }) .OrderByDescending(d => d.PairedValue.IsCustom) .Reverse() diff --git a/AgileMapper/TypeConversion/ToStringConverter.cs b/AgileMapper/TypeConversion/ToStringConverter.cs index 78c9dda64..165bf8da1 100644 --- a/AgileMapper/TypeConversion/ToStringConverter.cs +++ b/AgileMapper/TypeConversion/ToStringConverter.cs @@ -99,7 +99,7 @@ private static Expression GetDateTimeToStringConversion(Expression sourceValue, public static MethodInfo GetToStringMethodOrNull(Type sourceType, Type argumentType) { var toStringMethod = sourceType - .GetPublicInstanceMethods("ToString") + .GetPublicInstanceMethods(nameof(ToString)) .Project(m => new { Method = m, diff --git a/AgileMapper/Validation/EnumMappingMismatchFinder.cs b/AgileMapper/Validation/EnumMappingMismatchFinder.cs index 27d3e1839..27cb7d864 100644 --- a/AgileMapper/Validation/EnumMappingMismatchFinder.cs +++ b/AgileMapper/Validation/EnumMappingMismatchFinder.cs @@ -43,7 +43,7 @@ public static ICollection FindMismatches(ObjectMapperDat } var mismatchSets = targetMemberDatas - .Project(d => EnumMappingMismatchSet.For(d.TargetMember, d.DataSources, mapperData)) + .Project(mapperData, (md, d) => EnumMappingMismatchSet.For(d.TargetMember, d.DataSources, md)) .Filter(m => m.Any) .ToArray(); @@ -64,10 +64,10 @@ public static Expression Process(Expression lambda, ObjectMapperData mapperData) finder.Visit(lambda); var assignmentReplacements = finder._assignmentsByMismatchSet - .SelectMany(kvp => kvp.Value.Project(assignment => new + .SelectMany(kvp => kvp.Value.Project(kvp.Key, (k, assignment) => new { Assignment = assignment, - AssignmentWithWarning = (Expression)Expression.Block(kvp.Key.Warnings, assignment) + AssignmentWithWarning = (Expression)Expression.Block(k.Warnings, assignment) })) .ToDictionary(d => d.Assignment, d => d.AssignmentWithWarning); diff --git a/AgileMapper/Validation/EnumMappingMismatchSet.cs b/AgileMapper/Validation/EnumMappingMismatchSet.cs index fce6fc54b..df32e4ab6 100644 --- a/AgileMapper/Validation/EnumMappingMismatchSet.cs +++ b/AgileMapper/Validation/EnumMappingMismatchSet.cs @@ -221,7 +221,7 @@ private static void FilterOutConfiguredPairs( public string TargetMemberPath { get; } public string SourceMemberPaths => - _sourceMembers.Project(sm => sm.GetFriendlySourcePath(_rootMapperData)).Join(" / "); + _sourceMembers.Project(_rootMapperData, (rmd, sm) => sm.GetFriendlySourcePath(rmd)).Join(" / "); public string Warning => _warning ?? (_warning = CreateWarning()); diff --git a/AgileMapper/Validation/MappingValidator.cs b/AgileMapper/Validation/MappingValidator.cs index 26a8ded5c..f8efc1815 100644 --- a/AgileMapper/Validation/MappingValidator.cs +++ b/AgileMapper/Validation/MappingValidator.cs @@ -84,7 +84,6 @@ private static ICollection GetIncompleteMappingPlanData( UnmappedMembers = md .DataSourcesByTargetMember .Filter(pair => !pair.Value.HasValue) - .Project(pair => pair) .ToArray(), UnpairedEnums = EnumMappingMismatchFinder.FindMismatches(md) }) From 3e64e28ca8f83cedda2403f0d19e9d6349be00bf Mon Sep 17 00:00:00 2001 From: Steve Wilkes Date: Thu, 22 Aug 2019 11:04:52 +0100 Subject: [PATCH 5/8] Avoiding capture creation in .Filter() --- .../CustomDataSourceTargetMemberSpecifier.cs | 8 ++++---- AgileMapper/Api/PlanTargetSelector.cs | 2 +- .../Configuration/ConfiguredItemExtensions.cs | 2 +- .../Configuration/ConfiguredServiceProvider.cs | 2 +- AgileMapper/Configuration/DerivedTypePairSet.cs | 4 ++-- AgileMapper/Configuration/UserConfigurationSet.cs | 2 +- AgileMapper/DataSources/EnumerableDataSource.cs | 2 +- AgileMapper/Extensions/Internal/TypeExtensions.cs | 2 +- .../Extensions/PublicEnumerableExtensions.cs | 14 ++++++++++++++ AgileMapper/Members/MemberMapperDataExtensions.cs | 2 +- AgileMapper/Members/SourceMemberMatcher.cs | 7 +++---- .../ComplexTypes/ComplexTypeConstructionFactory.cs | 13 ++++++++----- .../DictionaryMappingExpressionFactory.cs | 2 +- .../Validation/EnumMappingMismatchFinder.cs | 4 ++-- AgileMapper/Validation/EnumMappingMismatchSet.cs | 2 +- 15 files changed, 42 insertions(+), 26 deletions(-) diff --git a/AgileMapper/Api/Configuration/CustomDataSourceTargetMemberSpecifier.cs b/AgileMapper/Api/Configuration/CustomDataSourceTargetMemberSpecifier.cs index ead642388..6a04e1c7f 100644 --- a/AgileMapper/Api/Configuration/CustomDataSourceTargetMemberSpecifier.cs +++ b/AgileMapper/Api/Configuration/CustomDataSourceTargetMemberSpecifier.cs @@ -284,14 +284,14 @@ private static ParameterInfo GetUniqueConstructorParameterOrThrow(string var matchingParameters = typeof(TTarget) .GetPublicInstanceConstructors() - .Project(settings, (s, ctor) => new + .Project(settings, (so, ctor) => new { Ctor = ctor, MatchingParameters = ctor .GetParameters() - .Filter(p => - (s.IgnoreParameterType || (p.ParameterType == typeof(TParam))) && - (s.IgnoreParameterName || (p.Name == name))) + .Filter(so, (si, p) => + (si.IgnoreParameterType || (p.ParameterType == typeof(TParam))) && + (si.IgnoreParameterName || (p.Name == name))) .ToArray() }) .Filter(d => d.MatchingParameters.Any()) diff --git a/AgileMapper/Api/PlanTargetSelector.cs b/AgileMapper/Api/PlanTargetSelector.cs index 00f15fdd8..b42cb7995 100644 --- a/AgileMapper/Api/PlanTargetSelector.cs +++ b/AgileMapper/Api/PlanTargetSelector.cs @@ -40,7 +40,7 @@ public MappingPlanSet To( _mapperContext .RuleSets .All - .Filter(ruleSet => ruleSet != _mapperContext.RuleSets.Project) + .Filter(_mapperContext, (mc, ruleSet) => ruleSet != mc.RuleSets.Project) .Project(configurations, (cs, rs) => GetMappingPlan(rs, cs)) .ToArray()); } diff --git a/AgileMapper/Configuration/ConfiguredItemExtensions.cs b/AgileMapper/Configuration/ConfiguredItemExtensions.cs index 2bbbb3758..e64c2f1f7 100644 --- a/AgileMapper/Configuration/ConfiguredItemExtensions.cs +++ b/AgileMapper/Configuration/ConfiguredItemExtensions.cs @@ -16,7 +16,7 @@ public static TItem FindMatch(this IList items, IBasicMapperData m public static IEnumerable FindMatches(this IEnumerable items, IBasicMapperData mapperData) where TItem : UserConfiguredItemBase { - return items?.Filter(item => item.AppliesTo(mapperData)) ?? Enumerable.Empty; + return items?.Filter(mapperData, (md, item) => item.AppliesTo(md)) ?? Enumerable.Empty; } } } \ No newline at end of file diff --git a/AgileMapper/Configuration/ConfiguredServiceProvider.cs b/AgileMapper/Configuration/ConfiguredServiceProvider.cs index 4544e8eb4..5c17fdd46 100644 --- a/AgileMapper/Configuration/ConfiguredServiceProvider.cs +++ b/AgileMapper/Configuration/ConfiguredServiceProvider.cs @@ -79,7 +79,7 @@ public static IEnumerable CreateFromOrThrow Array.IndexOf(_serviceProviderMethodNames, method.Name) != -1) + .Filter(_serviceProviderMethodNames, (spmns, method) => Array.IndexOf(spmns, method.Name) != -1) .Project(method => GetServiceProviderOrNull( method, providerObject, diff --git a/AgileMapper/Configuration/DerivedTypePairSet.cs b/AgileMapper/Configuration/DerivedTypePairSet.cs index 2a04730dd..96007e01b 100644 --- a/AgileMapper/Configuration/DerivedTypePairSet.cs +++ b/AgileMapper/Configuration/DerivedTypePairSet.cs @@ -78,7 +78,7 @@ public IList GetImplementationTypePairsFor( if (_typePairsByTargetType.TryGetValue(mapperData.TargetType, out var typePairs)) { return typePairs - .Filter(tp => tp.IsImplementationPairing && tp.AppliesTo(mapperData)) + .Filter(mapperData, (md, tp) => tp.IsImplementationPairing && tp.AppliesTo(md)) .ToArray(); } @@ -98,7 +98,7 @@ public IList GetDerivedTypePairsFor( if (_typePairsByTargetType.TryGetValue(mapperData.TargetType, out var typePairs)) { - return typePairs.Filter(tp => tp.AppliesTo(mapperData)).ToArray(); + return typePairs.Filter(mapperData, (md, tp) => tp.AppliesTo(md)).ToArray(); } return Enumerable.EmptyArray; diff --git a/AgileMapper/Configuration/UserConfigurationSet.cs b/AgileMapper/Configuration/UserConfigurationSet.cs index 4fd103bc9..7ee0576da 100644 --- a/AgileMapper/Configuration/UserConfigurationSet.cs +++ b/AgileMapper/Configuration/UserConfigurationSet.cs @@ -330,7 +330,7 @@ public IList GetMemberIgnoresFor(IBasicMapperData mappe } var ignoredMembers = _ignoredMembers - .Filter(im => im.CouldApplyTo(mapperData)) + .Filter(mapperData, (md, im) => im.CouldApplyTo(md)) .ToArray(); return ignoredMembers.Any() diff --git a/AgileMapper/DataSources/EnumerableDataSource.cs b/AgileMapper/DataSources/EnumerableDataSource.cs index 95ece2a2b..96e80a56a 100644 --- a/AgileMapper/DataSources/EnumerableDataSource.cs +++ b/AgileMapper/DataSources/EnumerableDataSource.cs @@ -100,7 +100,7 @@ private static bool IsNotMappingFromLinkingType( } var otherComplexTypeMembers = sourceElementMembers - .Filter(m => m.IsComplex && (m.Type != mapperData.SourceType)) + .Filter(mapperData, (md, m) => m.IsComplex && (m.Type != md.SourceType)) .ToArray(); if ((otherComplexTypeMembers.Length != 1) || diff --git a/AgileMapper/Extensions/Internal/TypeExtensions.cs b/AgileMapper/Extensions/Internal/TypeExtensions.cs index d16766bbe..83b398db9 100644 --- a/AgileMapper/Extensions/Internal/TypeExtensions.cs +++ b/AgileMapper/Extensions/Internal/TypeExtensions.cs @@ -123,7 +123,7 @@ public static Type[] GetCoercibleNumericTypes(this Type numericType) return Constants .NumericTypeMaxValuesByType - .Filter(kvp => kvp.Value < typeMaxValue) + .Filter(typeMaxValue, (tmv, kvp) => kvp.Value < tmv) .Project(kvp => kvp.Key) .ToArray(); } diff --git a/AgileMapper/Extensions/PublicEnumerableExtensions.cs b/AgileMapper/Extensions/PublicEnumerableExtensions.cs index 297b9bd5c..09dae05c9 100644 --- a/AgileMapper/Extensions/PublicEnumerableExtensions.cs +++ b/AgileMapper/Extensions/PublicEnumerableExtensions.cs @@ -86,6 +86,20 @@ public static IEnumerable Filter(this IEnumerable items, Fu } } + internal static IEnumerable Filter( + this IEnumerable items, + TArg argument, + Func predicate) + { + foreach (var item in items) + { + if (predicate.Invoke(argument, item)) + { + yield return item; + } + } + } + /// /// Exclude the given from these , in a /// repeated-item-aware manner. diff --git a/AgileMapper/Members/MemberMapperDataExtensions.cs b/AgileMapper/Members/MemberMapperDataExtensions.cs index e0757c065..08bb88ac6 100644 --- a/AgileMapper/Members/MemberMapperDataExtensions.cs +++ b/AgileMapper/Members/MemberMapperDataExtensions.cs @@ -323,7 +323,7 @@ private static bool TargetMemberEverRepeatsWithin(QualifiedMember parentMember, } var sameTypedChildMembers = nonSimpleChildMembers - .Filter(cm => (cm.IsEnumerable ? cm.ElementType : cm.Type) == subjectMember.Type) + .Filter(subjectMember, (sm, cm) => (cm.IsEnumerable ? cm.ElementType : cm.Type) == sm.Type) .ToArray(); if (sameTypedChildMembers diff --git a/AgileMapper/Members/SourceMemberMatcher.cs b/AgileMapper/Members/SourceMemberMatcher.cs index 1e5302f34..a61f8a14e 100644 --- a/AgileMapper/Members/SourceMemberMatcher.cs +++ b/AgileMapper/Members/SourceMemberMatcher.cs @@ -89,7 +89,7 @@ private static IEnumerable QuerySourceMembers( .Instance .MemberCache .GetSourceMembers(parentMember.Type) - .Filter(m => filter.Invoke(mapperData, m)); + .Filter(mapperData, filter.Invoke); if (!mapperData.RuleSet.Settings.AllowGetMethods) { @@ -100,14 +100,13 @@ private static IEnumerable QuerySourceMembers( if (mapperData.MapperContext.UserConfigurations.HasSourceMemberIgnores(mapperData)) { - qualifiedMembers = qualifiedMembers - .Filter(sm => IsNotUnconditionallyIgnored(sm, mapperData)); + qualifiedMembers = qualifiedMembers.Filter(mapperData, IsNotUnconditionallyIgnored); } return qualifiedMembers; } - private static bool IsNotUnconditionallyIgnored(IQualifiedMember sourceMember, IMemberMapperData mapperData) + private static bool IsNotUnconditionallyIgnored(IMemberMapperData mapperData, IQualifiedMember sourceMember) { var matchingIgnore = mapperData .MapperContext diff --git a/AgileMapper/ObjectPopulation/ComplexTypes/ComplexTypeConstructionFactory.cs b/AgileMapper/ObjectPopulation/ComplexTypes/ComplexTypeConstructionFactory.cs index ab692448c..0081d04cd 100644 --- a/AgileMapper/ObjectPopulation/ComplexTypes/ComplexTypeConstructionFactory.cs +++ b/AgileMapper/ObjectPopulation/ComplexTypes/ComplexTypeConstructionFactory.cs @@ -132,12 +132,12 @@ private static ConstructionDataInfo[] GetGreediestAvailableFactoryIn var candidateFactoryMethods = mapperData.TargetInstance.Type .GetPublicStaticMethods() - .Filter(m => IsFactoryMethod(m, mapperData.TargetInstance.Type)); + .Filter(mapperData.TargetInstance.Type, IsFactoryMethod); return CreateConstructionInfo(candidateFactoryMethods, fm => new FactoryMethodInfo(fm, key)); } - private static bool IsFactoryMethod(MethodInfo method, Type targetType) + private static bool IsFactoryMethod(Type targetType, MethodInfo method) { return (method.ReturnType == targetType) && (method.Name.StartsWith("Create", Ordinal) || method.Name.StartsWith("Get", Ordinal)); @@ -149,12 +149,12 @@ private static ConstructionDataInfo[] GetGreediestAvailableNewi IBasicConstructionInfo greediestUnconditionalFactoryInfo) { var candidateConstructors = constructors - .Filter(ctor => IsCandidateCtor(ctor, greediestUnconditionalFactoryInfo)); + .Filter(greediestUnconditionalFactoryInfo, IsCandidateCtor); return CreateConstructionInfo(candidateConstructors, ctor => new ObjectNewingInfo(ctor, key)); } - private static bool IsCandidateCtor(MethodBase ctor, IBasicConstructionInfo candidateFactoryMethod) + private static bool IsCandidateCtor(IBasicConstructionInfo candidateFactoryMethod, MethodBase ctor) { var ctorCarameters = ctor.GetParameters(); @@ -375,7 +375,10 @@ public void AddTo(IList constructionInfos, ConstructionKey ke { var dataSources = key.MappingData.MapperData.DataSourcesByTargetMember; - foreach (var dataSourceSet in ArgumentDataSources.Filter(ds => !dataSources.ContainsKey(ds.MapperData.TargetMember))) + var relevantDataSourceSets = ArgumentDataSources + .Filter(dataSources, (dss, ds) => !dss.ContainsKey(ds.MapperData.TargetMember)); + + foreach (var dataSourceSet in relevantDataSourceSets) { dataSources.Add(dataSourceSet.MapperData.TargetMember, dataSourceSet); } diff --git a/AgileMapper/ObjectPopulation/DictionaryMappingExpressionFactory.cs b/AgileMapper/ObjectPopulation/DictionaryMappingExpressionFactory.cs index 477b2a14f..34bf21cb3 100644 --- a/AgileMapper/ObjectPopulation/DictionaryMappingExpressionFactory.cs +++ b/AgileMapper/ObjectPopulation/DictionaryMappingExpressionFactory.cs @@ -38,7 +38,7 @@ private static IEnumerable GetAllTargetMembers(ObjectMapperData var configuredDataSourceFactories = mapperData.MapperContext .UserConfigurations .QueryDataSourceFactories() - .Filter(dsf => dsf.IsFor(mapperData)) + .Filter(mapperData, (md, dsf) => dsf.IsFor(md)) .ToArray(); if (configuredDataSourceFactories.None()) diff --git a/AgileMapper/Validation/EnumMappingMismatchFinder.cs b/AgileMapper/Validation/EnumMappingMismatchFinder.cs index 27cb7d864..1c1e31808 100644 --- a/AgileMapper/Validation/EnumMappingMismatchFinder.cs +++ b/AgileMapper/Validation/EnumMappingMismatchFinder.cs @@ -92,7 +92,7 @@ private static IEnumerable EnumerateTargetMemberDatas(ObjectMa var dataSources = targetMemberAndDataSource .Value - .Filter(dataSource => IsValidOtherEnumType(dataSource, targetEnumType)) + .Filter(targetEnumType, IsValidOtherEnumType) .ToArray(); if (dataSources.Any()) @@ -111,7 +111,7 @@ private static IEnumerable EnumerateTargetMemberDatas(ObjectMa } } - private static bool IsValidOtherEnumType(IDataSource dataSource, Type targetEnumType) + private static bool IsValidOtherEnumType(Type targetEnumType, IDataSource dataSource) { return dataSource.IsValid && IsEnum(dataSource.SourceMember.Type, out var sourceEnumType) && diff --git a/AgileMapper/Validation/EnumMappingMismatchSet.cs b/AgileMapper/Validation/EnumMappingMismatchSet.cs index df32e4ab6..c353aeb90 100644 --- a/AgileMapper/Validation/EnumMappingMismatchSet.cs +++ b/AgileMapper/Validation/EnumMappingMismatchSet.cs @@ -55,7 +55,7 @@ public static EnumMappingMismatchSet For( var targetEnumNames = Enum.GetNames(targetEnumType); var mappingMismatches = sourceEnumData - .Filter(d => d.EnumType != targetEnumType) + .Filter(targetEnumType, (tet, d) => d.EnumType != tet) .Project(d => EnumMappingMismatch.For( d.EnumType, d.SourceMembers, From 34e8102bdc07360d99a3bb412bc425b99126394c Mon Sep 17 00:00:00 2001 From: Steve Wilkes Date: Thu, 22 Aug 2019 11:16:49 +0100 Subject: [PATCH 6/8] Avoiding closure creation in .FirstOrDefault() --- .../Api/Configuration/EnumPairSpecifier.cs | 2 +- .../Configuration/ConfiguredItemExtensions.cs | 2 +- .../Configuration/DerivedTypePairSet.cs | 6 ++--- .../Dictionaries/DictionarySettings.cs | 2 +- .../Configuration/UserConfigurationSet.cs | 9 ++++--- AgileMapper/DataSources/DataSourceBase.cs | 2 +- .../DataSources/EnumerableDataSource.cs | 2 +- .../Factories/MaptimeDataSourcesFactory.cs | 2 +- .../Factories/MetaMemberDataSourcesFactory.cs | 4 +-- .../Internal/EnumerableExtensions.cs | 25 +++++++++++++++++-- AgileMapper/Members/MemberExtensions.cs | 2 +- .../ComplexTypeToNullComparisonConverter.cs | 3 ++- .../Settings/DefaultQueryProviderSettings.cs | 2 +- AgileMapper/TypeConversion/ToEnumConverter.cs | 2 +- .../Validation/EnumMappingMismatchFinder.cs | 2 +- 15 files changed, 45 insertions(+), 22 deletions(-) diff --git a/AgileMapper/Api/Configuration/EnumPairSpecifier.cs b/AgileMapper/Api/Configuration/EnumPairSpecifier.cs index 5a2c6316b..7a9307002 100644 --- a/AgileMapper/Api/Configuration/EnumPairSpecifier.cs +++ b/AgileMapper/Api/Configuration/EnumPairSpecifier.cs @@ -143,7 +143,7 @@ private void ThrowIfAlreadyPaired(TPairingEnum pairingEnumValue) var pairingEnumValueName = pairingEnumValue.ToString(); var confictingPairing = relevantPairings - .FirstOrDefault(ep => ep.PairingEnumMemberName == pairingEnumValueName); + .FirstOrDefault(pairingEnumValueName, (pevn, ep) => ep.PairingEnumMemberName == pevn); if (confictingPairing == null) { diff --git a/AgileMapper/Configuration/ConfiguredItemExtensions.cs b/AgileMapper/Configuration/ConfiguredItemExtensions.cs index e64c2f1f7..3d5ad41c1 100644 --- a/AgileMapper/Configuration/ConfiguredItemExtensions.cs +++ b/AgileMapper/Configuration/ConfiguredItemExtensions.cs @@ -10,7 +10,7 @@ internal static class ConfiguredItemExtensions public static TItem FindMatch(this IList items, IBasicMapperData mapperData) where TItem : UserConfiguredItemBase { - return items?.FirstOrDefault(item => item.AppliesTo(mapperData)); + return items?.FirstOrDefault(mapperData, (md, item) => item.AppliesTo(md)); } public static IEnumerable FindMatches(this IEnumerable items, IBasicMapperData mapperData) diff --git a/AgileMapper/Configuration/DerivedTypePairSet.cs b/AgileMapper/Configuration/DerivedTypePairSet.cs index 96007e01b..a7d95b605 100644 --- a/AgileMapper/Configuration/DerivedTypePairSet.cs +++ b/AgileMapper/Configuration/DerivedTypePairSet.cs @@ -62,8 +62,8 @@ private static void RemoveConflictingPairIfAppropriate( return; } - var existingTypePair = typePairs.FirstOrDefault(tp => - !tp.HasConfiguredCondition && (tp.DerivedSourceType == typePair.DerivedSourceType)); + var existingTypePair = typePairs.FirstOrDefault(typePair.DerivedSourceType, (dst, tp) => + !tp.HasConfiguredCondition && (tp.DerivedSourceType == dst)); if (existingTypePair != null) { @@ -166,7 +166,7 @@ private void LookForDerivedTypePairs(ITypePair mapperData, MapperContext mapperC foreach (var candidatePairData in candidatePairsData) { var derivedTargetType = derivedTargetTypes - .FirstOrDefault(t => t.Name == candidatePairData.DerivedTargetTypeName); + .FirstOrDefault(candidatePairData, (cpd, t) => t.Name == cpd.DerivedTargetTypeName); if (derivedTargetType == null) { diff --git a/AgileMapper/Configuration/Dictionaries/DictionarySettings.cs b/AgileMapper/Configuration/Dictionaries/DictionarySettings.cs index 97ef75ad2..20390bf7d 100644 --- a/AgileMapper/Configuration/Dictionaries/DictionarySettings.cs +++ b/AgileMapper/Configuration/Dictionaries/DictionarySettings.cs @@ -135,7 +135,7 @@ private static void ThrowIfConflictingKeyPartFactoryExists( } var conflictingFactory = existingFactories - .FirstOrDefault(kpf => kpf.ConflictsWith(factory)); + .FirstOrDefault(factory, (f, kpf) => kpf.ConflictsWith(f)); if (conflictingFactory == null) { diff --git a/AgileMapper/Configuration/UserConfigurationSet.cs b/AgileMapper/Configuration/UserConfigurationSet.cs index 7ee0576da..679bc13c0 100644 --- a/AgileMapper/Configuration/UserConfigurationSet.cs +++ b/AgileMapper/Configuration/UserConfigurationSet.cs @@ -75,7 +75,7 @@ public MappedObjectCachingMode CacheMappedObjects(IBasicMapperData basicData) } var applicableSettings = _mappedObjectCachingSettings - .FirstOrDefault(tm => tm.AppliesTo(basicData)); + .FirstOrDefault(basicData, (bd, tm) => tm.AppliesTo(bd)); if (applicableSettings == null) { @@ -135,7 +135,7 @@ public void Add(EntityKeyMappingSetting setting) public bool MapEntityKeys(IBasicMapperData basicData) { var applicableSetting = _entityKeyMappingSettings? - .FirstOrDefault(s => s.AppliesTo(basicData))? + .FirstOrDefault(basicData, (bd, s) => s.AppliesTo(bd))? .MapKeys; return (applicableSetting == true) || @@ -199,7 +199,8 @@ private bool AutoDataSourceReversalEnabled(T dataItem, Func s.AppliesTo(basicData))?.Reverse == true; + return _dataSourceReversalSettings + .FirstOrDefault(basicData, (bd, s) => s.AppliesTo(bd))?.Reverse == true; } #endregion @@ -554,7 +555,7 @@ private static void ThrowIfConflictingItemExists where TExistingItem : UserConfiguredItemBase { var conflictingItem = existingItems? - .FirstOrDefault(ci => ci.ConflictsWith(configuredItem)); + .FirstOrDefault(configuredItem, (sci, ci) => ci.ConflictsWith(sci)); if (conflictingItem == null) { diff --git a/AgileMapper/DataSources/DataSourceBase.cs b/AgileMapper/DataSources/DataSourceBase.cs index 785c671cb..f9931c6ca 100644 --- a/AgileMapper/DataSources/DataSourceBase.cs +++ b/AgileMapper/DataSources/DataSourceBase.cs @@ -168,7 +168,7 @@ private static bool IsNotOptionalEntityMemberId(IMemberMapperData mapperData) .Instance .MemberCache .GetTargetMembers(mapperData.TargetType) - .FirstOrDefault(m => m.Name == entityMemberName); + .FirstOrDefault(entityMemberName, (emn, m) => m.Name == emn); return !mapperData.IsEntity(entityMember?.Type, out _); } diff --git a/AgileMapper/DataSources/EnumerableDataSource.cs b/AgileMapper/DataSources/EnumerableDataSource.cs index 96e80a56a..b68f50644 100644 --- a/AgileMapper/DataSources/EnumerableDataSource.cs +++ b/AgileMapper/DataSources/EnumerableDataSource.cs @@ -91,7 +91,7 @@ private static bool IsNotMappingFromLinkingType( .GetSourceMembers(sourceElementType); var backLinkMember = sourceElementMembers - .FirstOrDefault(m => m.IsComplex && m.Type == mapperData.SourceType); + .FirstOrDefault(mapperData.SourceType, (st, m) => m.IsComplex && m.Type == st); if (backLinkMember == null) { diff --git a/AgileMapper/DataSources/Factories/MaptimeDataSourcesFactory.cs b/AgileMapper/DataSources/Factories/MaptimeDataSourcesFactory.cs index 34b2a8a93..425d67c3f 100644 --- a/AgileMapper/DataSources/Factories/MaptimeDataSourcesFactory.cs +++ b/AgileMapper/DataSources/Factories/MaptimeDataSourcesFactory.cs @@ -39,7 +39,7 @@ private static bool UseMaptimeDataSources( out IEnumerable maptimeDataSources) { var applicableFactory = _mapTimeDataSourceFactories - .FirstOrDefault(factory => factory.IsFor(context.MapperData)); + .FirstOrDefault(context.MapperData, (md, factory) => factory.IsFor(md)); if (applicableFactory == null) { diff --git a/AgileMapper/DataSources/Factories/MetaMemberDataSourcesFactory.cs b/AgileMapper/DataSources/Factories/MetaMemberDataSourcesFactory.cs index 94d1d2824..01ae5b3e1 100644 --- a/AgileMapper/DataSources/Factories/MetaMemberDataSourcesFactory.cs +++ b/AgileMapper/DataSources/Factories/MetaMemberDataSourcesFactory.cs @@ -192,14 +192,14 @@ private static bool TryGetMetaMember( var matchingTargetMember = GlobalContext.Instance .MemberCache .GetTargetMembers(currentMapperData.TargetType) - .FirstOrDefault(m => m.Name == memberNamePart); + .FirstOrDefault(memberNamePart, (mnp, m) => m.Name == mnp); if (matchingTargetMember == null) { matchingTargetMember = GlobalContext.Instance .MemberCache .GetSourceMembers(currentMapperData.SourceType) - .FirstOrDefault(m => m.Name == memberNamePart); + .FirstOrDefault(memberNamePart, (mnp, m) => m.Name == mnp); if (matchingTargetMember == null) { diff --git a/AgileMapper/Extensions/Internal/EnumerableExtensions.cs b/AgileMapper/Extensions/Internal/EnumerableExtensions.cs index 035733c0b..f09bc57e7 100644 --- a/AgileMapper/Extensions/Internal/EnumerableExtensions.cs +++ b/AgileMapper/Extensions/Internal/EnumerableExtensions.cs @@ -57,6 +57,10 @@ public static T First(this IList items, Func predicate) public static T FirstOrDefault(this IList items, Func predicate) => TryFindMatch(items, predicate, out var match) ? match : default(T); + [DebuggerStepThrough] + public static T FirstOrDefault(this IList items, TArg argument, Func predicate) + => TryFindMatch(items, argument, predicate, out var match) ? match : default(T); + [DebuggerStepThrough] public static IEnumerable TakeUntil(this IEnumerable items, Func predicate) { @@ -74,9 +78,9 @@ public static IEnumerable TakeUntil(this IEnumerable items, Func(this IList items, Func predicate, out T match) { - for (int i = 0, n = items.Count; i < n; i++) + for (int i = 0, n = items.Count; i < n;) { - match = items[i]; + match = items[i++]; if (predicate.Invoke(match)) { @@ -88,6 +92,23 @@ public static bool TryFindMatch(this IList items, Func predicate, return false; } + [DebuggerStepThrough] + public static bool TryFindMatch(this IList items, TArg argument, Func predicate, out T match) + { + for (int i = 0, n = items.Count; i < n;) + { + match = items[i++]; + + if (predicate.Invoke(argument, match)) + { + return true; + } + } + + match = default(T); + return false; + } + [DebuggerStepThrough] public static T Last(this IList items) => items[items.Count - 1]; diff --git a/AgileMapper/Members/MemberExtensions.cs b/AgileMapper/Members/MemberExtensions.cs index 2cba794f5..ac1f417e6 100644 --- a/AgileMapper/Members/MemberExtensions.cs +++ b/AgileMapper/Members/MemberExtensions.cs @@ -395,7 +395,7 @@ private static QualifiedMember CreateMember( var memberAccess = memberAccesses[i++]; var memberName = GetMemberName(memberAccess); var members = membersFactory.Invoke(parentMember.Type); - var member = members.FirstOrDefault(m => m.Name == memberName); + var member = members.FirstOrDefault(memberName, (mn, m) => m.Name == mn); if (member == null) { diff --git a/AgileMapper/Queryables/Converters/ComplexTypeToNullComparisonConverter.cs b/AgileMapper/Queryables/Converters/ComplexTypeToNullComparisonConverter.cs index c2991bc57..4635af4e3 100644 --- a/AgileMapper/Queryables/Converters/ComplexTypeToNullComparisonConverter.cs +++ b/AgileMapper/Queryables/Converters/ComplexTypeToNullComparisonConverter.cs @@ -118,7 +118,8 @@ private static bool TryGetEntityMemberIdMember( { idMemberName = entityMemberName + idMemberName; - entityMemberIdMember = sourceMembers.FirstOrDefault(m => m.Name.EqualsIgnoreCase(idMemberName)); + entityMemberIdMember = sourceMembers + .FirstOrDefault(idMemberName, (idmn, m) => m.Name.EqualsIgnoreCase(idmn)); return entityMemberIdMember != null; } diff --git a/AgileMapper/Queryables/Settings/DefaultQueryProviderSettings.cs b/AgileMapper/Queryables/Settings/DefaultQueryProviderSettings.cs index 22fe0d7ab..be3ed0657 100644 --- a/AgileMapper/Queryables/Settings/DefaultQueryProviderSettings.cs +++ b/AgileMapper/Queryables/Settings/DefaultQueryProviderSettings.cs @@ -130,7 +130,7 @@ private static Assembly GetAssemblyOrNull(string loadedAssemblyName) return AppDomain.CurrentDomain .GetAssemblies() - .FirstOrDefault(assembly => assembly.GetName().Name == assemblyName); + .FirstOrDefault(assemblyName, (an, assembly) => assembly.GetName().Name == an); #endif } diff --git a/AgileMapper/TypeConversion/ToEnumConverter.cs b/AgileMapper/TypeConversion/ToEnumConverter.cs index a1436d284..ec810400c 100644 --- a/AgileMapper/TypeConversion/ToEnumConverter.cs +++ b/AgileMapper/TypeConversion/ToEnumConverter.cs @@ -387,7 +387,7 @@ private Expression GetEnumToEnumConversion( return new { Value = targetEnumValues - .FirstOrDefault(tv => tv.Member.Name.EqualsIgnoreCase(sv.Member.Name)) ?? + .FirstOrDefault(sv.Member.Name, (name, tv) => tv.Member.Name.EqualsIgnoreCase(name)) ?? fallbackValue, IsCustom = false }; diff --git a/AgileMapper/Validation/EnumMappingMismatchFinder.cs b/AgileMapper/Validation/EnumMappingMismatchFinder.cs index 1c1e31808..d6f319820 100644 --- a/AgileMapper/Validation/EnumMappingMismatchFinder.cs +++ b/AgileMapper/Validation/EnumMappingMismatchFinder.cs @@ -163,7 +163,7 @@ private bool TryGetMatch(Expression targetMemberAccess, out TargetMemberData tar var memberName = targetMemberAccess.GetMemberName(); targetMemberData = _targetMemberDatas - .FirstOrDefault(dss => dss.TargetMember.Name == memberName); + .FirstOrDefault(memberName, (mn, dss) => dss.TargetMember.Name == mn); return targetMemberData != null; } From 97a4dbf2baba98fea2155f77ded43ada6b0d4820 Mon Sep 17 00:00:00 2001 From: Steve Wilkes Date: Thu, 22 Aug 2019 11:21:49 +0100 Subject: [PATCH 7/8] Avoiding closure creation in .First() --- AgileMapper/Configuration/UserConfigurationSet.cs | 2 +- .../DataSources/Factories/DataSourceSetFactory.cs | 2 +- .../Extensions/Internal/EnumerableExtensions.cs | 11 +++++++++++ .../Extensions/Internal/StringExpressionExtensions.cs | 2 +- AgileMapper/MappingRuleSetCollection.cs | 2 +- .../ComplexTypeMappingExpressionFactory.cs | 2 +- AgileMapper/TypeConversion/ToEnumConverter.cs | 2 +- 7 files changed, 17 insertions(+), 6 deletions(-) diff --git a/AgileMapper/Configuration/UserConfigurationSet.cs b/AgileMapper/Configuration/UserConfigurationSet.cs index 679bc13c0..f45d87cf0 100644 --- a/AgileMapper/Configuration/UserConfigurationSet.cs +++ b/AgileMapper/Configuration/UserConfigurationSet.cs @@ -390,7 +390,7 @@ public void Add(ConfiguredDataSourceFactory dataSourceFactory) } public ConfiguredDataSourceFactory GetDataSourceFactoryFor(MappingConfigInfo configInfo) - => _dataSourceFactories.First(dsf => dsf.ConfigInfo == configInfo); + => _dataSourceFactories.First(configInfo, (ci, dsf) => dsf.ConfigInfo == ci); public bool HasConfiguredToTargetDataSources { get; private set; } diff --git a/AgileMapper/DataSources/Factories/DataSourceSetFactory.cs b/AgileMapper/DataSources/Factories/DataSourceSetFactory.cs index 031e57aa7..6e6e291c7 100644 --- a/AgileMapper/DataSources/Factories/DataSourceSetFactory.cs +++ b/AgileMapper/DataSources/Factories/DataSourceSetFactory.cs @@ -29,7 +29,7 @@ internal static class DataSourceSetFactory public static DataSourceSet CreateFor(IObjectMappingData rootMappingData) { var rootDataSourceFactory = _mappingRootDataSourceFactories - .First(mef => mef.IsFor(rootMappingData)); + .First(rootMappingData, (rmd, mef) => mef.IsFor(rmd)); var rootDataSource = rootDataSourceFactory.CreateFor(rootMappingData); diff --git a/AgileMapper/Extensions/Internal/EnumerableExtensions.cs b/AgileMapper/Extensions/Internal/EnumerableExtensions.cs index f09bc57e7..0b8943962 100644 --- a/AgileMapper/Extensions/Internal/EnumerableExtensions.cs +++ b/AgileMapper/Extensions/Internal/EnumerableExtensions.cs @@ -53,6 +53,17 @@ public static T First(this IList items, Func predicate) throw new InvalidOperationException("Sequence contains no matching element"); } + [DebuggerStepThrough] + public static T First(this IList items, TArg argument, Func predicate) + { + if (TryFindMatch(items, argument, predicate, out var match)) + { + return match; + } + + throw new InvalidOperationException("Sequence contains no matching element"); + } + [DebuggerStepThrough] public static T FirstOrDefault(this IList items, Func predicate) => TryFindMatch(items, predicate, out var match) ? match : default(T); diff --git a/AgileMapper/Extensions/Internal/StringExpressionExtensions.cs b/AgileMapper/Extensions/Internal/StringExpressionExtensions.cs index 09e9b767a..ed54c48fc 100644 --- a/AgileMapper/Extensions/Internal/StringExpressionExtensions.cs +++ b/AgileMapper/Extensions/Internal/StringExpressionExtensions.cs @@ -58,7 +58,7 @@ public static Expression GetIsNullOrWhiteSpaceCall(Expression stringValue) } public static MethodInfo GetConcatMethod(int parameterCount) - => _stringConcatMethods.First(m => m.GetParameters().Length == parameterCount); + => _stringConcatMethods.First(parameterCount, (pc, m) => m.GetParameters().Length == pc); public static Expression GetStringConcatCall(this IList expressions) { diff --git a/AgileMapper/MappingRuleSetCollection.cs b/AgileMapper/MappingRuleSetCollection.cs index ee1bcac25..28dd37d60 100644 --- a/AgileMapper/MappingRuleSetCollection.cs +++ b/AgileMapper/MappingRuleSetCollection.cs @@ -80,6 +80,6 @@ public MappingRuleSetCollection(params MappingRuleSet[] ruleSets) public MappingRuleSet Project => _project; - public MappingRuleSet GetByName(string name) => All.First(rs => rs.Name == name); + public MappingRuleSet GetByName(string name) => All.First(name, (n, rs) => rs.Name == n); } } \ No newline at end of file diff --git a/AgileMapper/ObjectPopulation/ComplexTypes/ComplexTypeMappingExpressionFactory.cs b/AgileMapper/ObjectPopulation/ComplexTypes/ComplexTypeMappingExpressionFactory.cs index b3c26b330..a2762e877 100644 --- a/AgileMapper/ObjectPopulation/ComplexTypes/ComplexTypeMappingExpressionFactory.cs +++ b/AgileMapper/ObjectPopulation/ComplexTypes/ComplexTypeMappingExpressionFactory.cs @@ -190,7 +190,7 @@ private static Expression GetAlreadyMappedObjectShortCircuitOrNull(ObjectMapperD } private bool TryGetShortCircuitFactory(ObjectMapperData mapperData, out ISourceShortCircuitFactory applicableFactory) - => _shortCircuitFactories.TryFindMatch(f => f.IsFor(mapperData), out applicableFactory); + => _shortCircuitFactories.TryFindMatch(mapperData, (md, f) => f.IsFor(md), out applicableFactory); #endregion diff --git a/AgileMapper/TypeConversion/ToEnumConverter.cs b/AgileMapper/TypeConversion/ToEnumConverter.cs index ec810400c..708d25302 100644 --- a/AgileMapper/TypeConversion/ToEnumConverter.cs +++ b/AgileMapper/TypeConversion/ToEnumConverter.cs @@ -379,7 +379,7 @@ private Expression GetEnumToEnumConversion( { return new { - Value = (Expression)targetEnumValues.First(tv => tv.Member.Name == pairedMemberName), + Value = (Expression)targetEnumValues.First(pairedMemberName, (pmn, tv) => tv.Member.Name == pmn), IsCustom = true }; } From 5431b92ac142e48cf0a7849e2d4729e45608162e Mon Sep 17 00:00:00 2001 From: Steve Wilkes Date: Thu, 22 Aug 2019 12:30:28 +0100 Subject: [PATCH 8/8] Reusing MemberPopulationContext and DataSourceFindContext throughout complex type member population creation --- .../Configuration/ConfiguredItemExtensions.cs | 7 ++ .../Configuration/UserConfigurationSet.cs | 37 +++------ .../Factories/DataSourceFindContext.cs | 81 +++++++++++++------ .../Factories/DataSourceSetFactory.cs | 6 +- .../Factories/MaptimeDataSourcesFactory.cs | 4 +- .../Factories/MetaMemberDataSourcesFactory.cs | 14 ++-- .../SourceMemberDataSourcesFactory.cs | 13 ++- .../Population/MemberPopulationContext.cs | 37 ++++++--- .../Population/MemberPopulatorFactory.cs | 4 +- .../ComplexTypeConstructionFactory.cs | 2 +- 10 files changed, 120 insertions(+), 85 deletions(-) diff --git a/AgileMapper/Configuration/ConfiguredItemExtensions.cs b/AgileMapper/Configuration/ConfiguredItemExtensions.cs index 3d5ad41c1..873565733 100644 --- a/AgileMapper/Configuration/ConfiguredItemExtensions.cs +++ b/AgileMapper/Configuration/ConfiguredItemExtensions.cs @@ -1,6 +1,7 @@ namespace AgileObjects.AgileMapper.Configuration { using System.Collections.Generic; + using System.Linq; using Extensions; using Extensions.Internal; using Members; @@ -18,5 +19,11 @@ public static IEnumerable FindMatches(this IEnumerable item { return items?.Filter(mapperData, (md, item) => item.AppliesTo(md)) ?? Enumerable.Empty; } + + public static IList FindPotentialMatches(this IEnumerable items, IBasicMapperData mapperData) + where TItem : UserConfiguredItemBase + { + return items?.Filter(mapperData, (md, item) => item.CouldApplyTo(md)).ToArray() ?? Enumerable.EmptyArray; + } } } \ No newline at end of file diff --git a/AgileMapper/Configuration/UserConfigurationSet.cs b/AgileMapper/Configuration/UserConfigurationSet.cs index f45d87cf0..bc42b89f4 100644 --- a/AgileMapper/Configuration/UserConfigurationSet.cs +++ b/AgileMapper/Configuration/UserConfigurationSet.cs @@ -323,21 +323,8 @@ public void Add(ConfiguredIgnoredMember ignoredMember) IgnoredMembers.AddSortFilter(ignoredMember); } - public IList GetMemberIgnoresFor(IBasicMapperData mapperData) - { - if (_ignoredMembers == null) - { - return Enumerable.EmptyArray; - } - - var ignoredMembers = _ignoredMembers - .Filter(mapperData, (md, im) => im.CouldApplyTo(md)) - .ToArray(); - - return ignoredMembers.Any() - ? ignoredMembers - : Enumerable.EmptyArray; - } + public IList GetPotentialMemberIgnores(IBasicMapperData mapperData) + => _ignoredMembers.FindPotentialMatches(mapperData); #endregion @@ -394,8 +381,8 @@ public ConfiguredDataSourceFactory GetDataSourceFactoryFor(MappingConfigInfo con public bool HasConfiguredToTargetDataSources { get; private set; } - public IList GetDataSources(IMemberMapperData mapperData) - => GetDataSources(QueryDataSourceFactories(mapperData), mapperData); + public IList GetPotentialDataSourceFactories(IMemberMapperData mapperData) + => _dataSourceFactories.FindPotentialMatches(mapperData); public IList GetDataSourcesForToTarget(IMemberMapperData mapperData) { @@ -404,18 +391,12 @@ public IList GetDataSourcesForToTarget(IMemberMapperData return Enumerable.EmptyArray; } - var toTargetDataSourceFactories = - QueryDataSourceFactories(mapperData) - .Filter(dsf => dsf.TargetMember.IsRoot); - - return GetDataSources(toTargetDataSourceFactories, mapperData); - } + var toTargetDataSources = QueryDataSourceFactories(mapperData) + .Filter(dsf => dsf.TargetMember.IsRoot) + .Project(mapperData, (md, dsf) => dsf.Create(md)) + .ToArray(); - private static IList GetDataSources( - IEnumerable factories, - IMemberMapperData mapperData) - { - return factories.Project(mapperData, (md, dsf) => dsf.Create(md)).ToArray(); + return toTargetDataSources; } public IEnumerable QueryDataSourceFactories(IBasicMapperData mapperData) diff --git a/AgileMapper/DataSources/Factories/DataSourceFindContext.cs b/AgileMapper/DataSources/Factories/DataSourceFindContext.cs index 6626a0716..12d41c773 100644 --- a/AgileMapper/DataSources/Factories/DataSourceFindContext.cs +++ b/AgileMapper/DataSources/Factories/DataSourceFindContext.cs @@ -1,51 +1,77 @@ namespace AgileObjects.AgileMapper.DataSources.Factories { using System.Collections.Generic; + using System.Linq; + using Configuration; using Extensions; using Extensions.Internal; using Members; internal class DataSourceFindContext { - public DataSourceFindContext(IChildMemberMappingData childMappingData) + private IList _potentialConfiguredDataSourceFactories; + private IList _configuredDataSources; + + public DataSourceFindContext(IChildMemberMappingData memberMappingData) { - ChildMappingData = childMappingData; + MemberMappingData = memberMappingData; + } - ConfiguredDataSources = GetConfiguredDataSources(MapperData); + public MapperContext MapperContext => MemberMapperData.MapperContext; - if (!MapperData.Parent.Context.IsForToTargetMapping) - { - return; - } + public IChildMemberMappingData MemberMappingData { get; private set; } - var originalChildMapperData = new ChildMemberMapperData( - MapperData.TargetMember, - MapperData.Parent.OriginalMapperData); + public IMemberMapperData MemberMapperData => MemberMappingData.MapperData; - ConfiguredDataSources = ConfiguredDataSources.Append( - GetConfiguredDataSources(originalChildMapperData)); - } + public QualifiedMember TargetMember => MemberMapperData.TargetMember; - private IList GetConfiguredDataSources(IMemberMapperData mapperData) - => MapperContext.UserConfigurations.GetDataSources(mapperData); + public int DataSourceIndex { get; set; } - public IChildMemberMappingData ChildMappingData { get; } + public bool StopFind { get; set; } - public IMemberMapperData MapperData => ChildMappingData.MapperData; + private IEnumerable PotentialConfiguredDataSourceFactories + => _potentialConfiguredDataSourceFactories ?? + (_potentialConfiguredDataSourceFactories = GetPotentialConfiguredDataSourceFactories()); - public MapperContext MapperContext => MapperData.MapperContext; + private IList GetPotentialConfiguredDataSourceFactories() + { + var potentialDataSourceFactories = GetPotentialConfiguredDataSourceFactories(MemberMapperData); - public int DataSourceIndex { get; set; } + if (!MemberMapperData.Parent.Context.IsForToTargetMapping) + { + return potentialDataSourceFactories; + } - public bool StopFind { get; set; } + var originalChildMapperData = new ChildMemberMapperData( + TargetMember, + MemberMapperData.Parent.OriginalMapperData); + + potentialDataSourceFactories = potentialDataSourceFactories.Append( + GetPotentialConfiguredDataSourceFactories(originalChildMapperData)); + + return potentialDataSourceFactories; + } + + private IList GetPotentialConfiguredDataSourceFactories(IMemberMapperData mapperData) + => MapperContext.UserConfigurations.GetPotentialDataSourceFactories(mapperData); - public IList ConfiguredDataSources { get; } + public IList ConfiguredDataSources + { + get + { + return _configuredDataSources ?? (_configuredDataSources = + PotentialConfiguredDataSourceFactories + .FindMatches(MemberMapperData) + .Project(MemberMapperData, (md, dsf) => dsf.Create(md)) + .ToArray()); + } + } public IDataSource GetFallbackDataSource() - => ChildMappingData.RuleSet.FallbackDataSourceFactory.Invoke(MapperData); + => MemberMappingData.RuleSet.FallbackDataSourceFactory.Invoke(MemberMapperData); public IDataSource GetFinalDataSource(IDataSource foundDataSource) - => GetFinalDataSource(foundDataSource, ChildMappingData); + => GetFinalDataSource(foundDataSource, MemberMappingData); public IDataSource GetFinalDataSource(IDataSource foundDataSource, IChildMemberMappingData mappingData) { @@ -89,5 +115,14 @@ private static bool UseComplexTypeDataSource(IDataSource dataSource, QualifiedMe return !targetMember.Type.IsFromBcl(); } + + public DataSourceFindContext With(IChildMemberMappingData memberMappingData) + { + MemberMappingData = memberMappingData; + _configuredDataSources = null; + DataSourceIndex = 0; + StopFind = false; + return this; + } } } \ No newline at end of file diff --git a/AgileMapper/DataSources/Factories/DataSourceSetFactory.cs b/AgileMapper/DataSources/Factories/DataSourceSetFactory.cs index 6e6e291c7..c25b72e41 100644 --- a/AgileMapper/DataSources/Factories/DataSourceSetFactory.cs +++ b/AgileMapper/DataSources/Factories/DataSourceSetFactory.cs @@ -4,7 +4,6 @@ using System.Linq; using Extensions.Internal; using MappingRoot; - using Members; using ObjectPopulation; internal static class DataSourceSetFactory @@ -36,12 +35,11 @@ public static DataSourceSet CreateFor(IObjectMappingData rootMappingData) return DataSourceSet.For(rootDataSource, rootMappingData.MapperData); } - public static DataSourceSet CreateFor(IChildMemberMappingData childMappingData) + public static DataSourceSet CreateFor(DataSourceFindContext findContext) { - var findContext = new DataSourceFindContext(childMappingData); var validDataSources = EnumerateDataSources(findContext).ToArray(); - return DataSourceSet.For(validDataSources, findContext.MapperData); + return DataSourceSet.For(validDataSources, findContext.MemberMapperData); } private static IEnumerable EnumerateDataSources(DataSourceFindContext context) diff --git a/AgileMapper/DataSources/Factories/MaptimeDataSourcesFactory.cs b/AgileMapper/DataSources/Factories/MaptimeDataSourcesFactory.cs index 425d67c3f..ca17d245d 100644 --- a/AgileMapper/DataSources/Factories/MaptimeDataSourcesFactory.cs +++ b/AgileMapper/DataSources/Factories/MaptimeDataSourcesFactory.cs @@ -39,7 +39,7 @@ private static bool UseMaptimeDataSources( out IEnumerable maptimeDataSources) { var applicableFactory = _mapTimeDataSourceFactories - .FirstOrDefault(context.MapperData, (md, factory) => factory.IsFor(md)); + .FirstOrDefault(context.MemberMapperData, (md, factory) => factory.IsFor(md)); if (applicableFactory == null) { @@ -47,7 +47,7 @@ private static bool UseMaptimeDataSources( return false; } - maptimeDataSources = applicableFactory.Create(context.ChildMappingData); + maptimeDataSources = applicableFactory.Create(context.MemberMappingData); return true; } } diff --git a/AgileMapper/DataSources/Factories/MetaMemberDataSourcesFactory.cs b/AgileMapper/DataSources/Factories/MetaMemberDataSourcesFactory.cs index 01ae5b3e1..f24195f37 100644 --- a/AgileMapper/DataSources/Factories/MetaMemberDataSourcesFactory.cs +++ b/AgileMapper/DataSources/Factories/MetaMemberDataSourcesFactory.cs @@ -41,7 +41,7 @@ private static bool TryGetMetaMemberNameParts( { memberNameParts = default(IList); - var targetMemberName = context.MapperData.TargetMember.Name; + var targetMemberName = context.TargetMember.Name; var previousNamePartEndIndex = targetMemberName.Length; var currentMemberName = string.Empty; var noMetaMemberAdded = true; @@ -140,7 +140,7 @@ private static bool TryGetMetaMember( var currentMemberPart = metaMember = default(MetaMemberPartBase); Func currentMappingDataFactory = - (sm, tm, md, c) => c.ChildMappingData.Parent; + (sm, tm, md, c) => c.MemberMappingData.Parent; for (var i = memberNameParts.Count - 1; i >= 0; --i) { @@ -149,7 +149,7 @@ private static bool TryGetMetaMember( switch (memberNamePart) { case HasMetaMemberPart.Name: - if (HasMetaMemberPart.TryCreateFor(context.MapperData, ref currentMemberPart)) + if (HasMetaMemberPart.TryCreateFor(context.MemberMapperData, ref currentMemberPart)) { break; } @@ -157,15 +157,15 @@ private static bool TryGetMetaMember( return false; case FirstMetaMemberPart.Name: - currentMemberPart = new FirstMetaMemberPart(context.MapperData); + currentMemberPart = new FirstMetaMemberPart(context.MemberMapperData); break; case LastMetaMemberPart.Name: - currentMemberPart = new LastMetaMemberPart(context.MapperData); + currentMemberPart = new LastMetaMemberPart(context.MemberMapperData); break; case CountMetaMemberPart.Name: - if (CountMetaMemberPart.TryCreateFor(context.MapperData, ref currentMemberPart)) + if (CountMetaMemberPart.TryCreateFor(context.MemberMapperData, ref currentMemberPart)) { break; } @@ -173,7 +173,7 @@ private static bool TryGetMetaMember( return false; case NumberOfMetaMemberPart.Name: - if (NumberOfMetaMemberPart.TryCreateFor(context.MapperData, ref currentMemberPart)) + if (NumberOfMetaMemberPart.TryCreateFor(context.MemberMapperData, ref currentMemberPart)) { break; } diff --git a/AgileMapper/DataSources/Factories/SourceMemberDataSourcesFactory.cs b/AgileMapper/DataSources/Factories/SourceMemberDataSourcesFactory.cs index 17d3d7528..f052dce9c 100644 --- a/AgileMapper/DataSources/Factories/SourceMemberDataSourcesFactory.cs +++ b/AgileMapper/DataSources/Factories/SourceMemberDataSourcesFactory.cs @@ -8,14 +8,14 @@ internal static class SourceMemberDataSourcesFactory { public static IEnumerable Create(DataSourceFindContext context) { - if (context.MapperData.TargetMember.IsCustom) + if (context.TargetMember.IsCustom) { yield break; } var matchingSourceMemberDataSource = GetSourceMemberDataSource(context, out var hasUseableSourceMember); var configuredDataSources = context.ConfiguredDataSources; - var targetMember = context.MapperData.TargetMember; + var targetMember = context.TargetMember; if (!hasUseableSourceMember || configuredDataSources.Any(cds => cds.IsSameAs(matchingSourceMemberDataSource))) @@ -24,7 +24,7 @@ public static IEnumerable Create(DataSourceFindContext context) { if (UseFallbackComplexTypeDataSource(targetMember)) { - yield return ComplexTypeDataSource.Create(context.DataSourceIndex, context.ChildMappingData); + yield return ComplexTypeDataSource.Create(context.DataSourceIndex, context.MemberMappingData); } } else if (configuredDataSources.Any() && configuredDataSources.Last().IsConditional) @@ -40,15 +40,14 @@ public static IEnumerable Create(DataSourceFindContext context) } if (matchingSourceMemberDataSource.SourceMember.IsSimple && - context.MapperData.MapperContext.UserConfigurations.HasConfiguredToTargetDataSources) + context.MapperContext.UserConfigurations.HasConfiguredToTargetDataSources) { var updatedMapperData = new ChildMemberMapperData( matchingSourceMemberDataSource.SourceMember, targetMember, - context.MapperData.Parent); + context.MemberMapperData.Parent); var configuredRootDataSources = context - .MapperData .MapperContext .UserConfigurations .GetDataSourcesForToTarget(updatedMapperData); @@ -73,7 +72,7 @@ private static IDataSource GetSourceMemberDataSource( DataSourceFindContext context, out bool hasUseableSourceMember) { - var bestSourceMemberMatch = SourceMemberMatcher.GetMatchFor(context.ChildMappingData); + var bestSourceMemberMatch = SourceMemberMatcher.GetMatchFor(context.MemberMappingData); hasUseableSourceMember = bestSourceMemberMatch.IsUseable; if (hasUseableSourceMember) diff --git a/AgileMapper/Members/Population/MemberPopulationContext.cs b/AgileMapper/Members/Population/MemberPopulationContext.cs index 5c97a85fc..bd907b8d5 100644 --- a/AgileMapper/Members/Population/MemberPopulationContext.cs +++ b/AgileMapper/Members/Population/MemberPopulationContext.cs @@ -7,12 +7,14 @@ namespace AgileObjects.AgileMapper.Members.Population using System.Linq.Expressions; #endif using Configuration; + using DataSources.Factories; using ObjectPopulation; internal class MemberPopulationContext { - private IList _memberIgnores; + private IList _potentialMemberIgnores; private ConfiguredIgnoredMember _memberIgnore; + private DataSourceFindContext _dataSourceFindContext; public MemberPopulationContext(IObjectMappingData mappingData) { @@ -37,18 +39,12 @@ public MemberPopulationContext(IObjectMappingData mappingData) public bool AddUnsuccessfulMemberPopulations => MappingContext.AddUnsuccessfulMemberPopulations; - public MemberPopulationContext With(QualifiedMember targetMember) - { - MemberMapperData = new ChildMemberMapperData(targetMember, MapperData); - _memberIgnore = null; - return this; - } - - private IList MemberIgnores - => _memberIgnores ?? (_memberIgnores = UserConfigurations.GetMemberIgnoresFor(MemberMapperData)); + private IList PotentialMemberIgnores + => _potentialMemberIgnores ?? + (_potentialMemberIgnores = UserConfigurations.GetPotentialMemberIgnores(MemberMapperData)); public ConfiguredIgnoredMember MemberIgnore - => _memberIgnore ?? (_memberIgnore = MemberIgnores.FindMatch(MemberMapperData)); + => _memberIgnore ?? (_memberIgnore = PotentialMemberIgnores.FindMatch(MemberMapperData)); public bool TargetMemberIsUnconditionallyIgnored(out Expression populateCondition) { @@ -61,5 +57,24 @@ public bool TargetMemberIsUnconditionallyIgnored(out Expression populateConditio populateCondition = _memberIgnore.GetConditionOrNull(MemberMapperData); return (populateCondition == null); } + + public DataSourceFindContext GetDataSourceFindContext() + { + var memberMappingData = MappingData.GetChildMappingData(MemberMapperData); + + if (_dataSourceFindContext == null) + { + _dataSourceFindContext = new DataSourceFindContext(memberMappingData); + } + + return _dataSourceFindContext.With(memberMappingData); + } + + public MemberPopulationContext With(QualifiedMember targetMember) + { + MemberMapperData = new ChildMemberMapperData(targetMember, MapperData); + _memberIgnore = null; + return this; + } } } \ No newline at end of file diff --git a/AgileMapper/Members/Population/MemberPopulatorFactory.cs b/AgileMapper/Members/Population/MemberPopulatorFactory.cs index 7e020a3fd..91ae9f837 100644 --- a/AgileMapper/Members/Population/MemberPopulatorFactory.cs +++ b/AgileMapper/Members/Population/MemberPopulatorFactory.cs @@ -45,8 +45,8 @@ private static IMemberPopulator Create(MemberPopulationContext context) return MemberPopulator.IgnoredMember(context); } - var childMappingData = context.MappingData.GetChildMappingData(context.MemberMapperData); - var dataSources = DataSourceSetFactory.CreateFor(childMappingData); + var dataSourceFindContext = context.GetDataSourceFindContext(); + var dataSources = DataSourceSetFactory.CreateFor(dataSourceFindContext); if (dataSources.None) { diff --git a/AgileMapper/ObjectPopulation/ComplexTypes/ComplexTypeConstructionFactory.cs b/AgileMapper/ObjectPopulation/ComplexTypes/ComplexTypeConstructionFactory.cs index 0081d04cd..59134fb48 100644 --- a/AgileMapper/ObjectPopulation/ComplexTypes/ComplexTypeConstructionFactory.cs +++ b/AgileMapper/ObjectPopulation/ComplexTypes/ComplexTypeConstructionFactory.cs @@ -359,7 +359,7 @@ private static DataSourceSet[] GetArgumentDataSources(TInvokable invokable, Cons key.MappingData.MapperData); var memberMappingData = key.MappingData.GetChildMappingData(parameterMapperData); - var dataSources = DataSourceSetFactory.CreateFor(memberMappingData); + var dataSources = DataSourceSetFactory.CreateFor(new DataSourceFindContext(memberMappingData)); return dataSources; });