diff --git a/AgileMapper.UnitTests.Net35/AgileMapper.UnitTests.Net35.csproj b/AgileMapper.UnitTests.Net35/AgileMapper.UnitTests.Net35.csproj
index 70e14fb2b..c014778c5 100644
--- a/AgileMapper.UnitTests.Net35/AgileMapper.UnitTests.Net35.csproj
+++ b/AgileMapper.UnitTests.Net35/AgileMapper.UnitTests.Net35.csproj
@@ -66,8 +66,599 @@
-
- %(RecursiveDir)%(Filename)%(Extension)
+
+ Caching\WhenCachingWithHashCodes.cs
+
+
+ Configuration\AssemblyScanningTestClassBase.cs
+
+
+ Configuration\Inline\InlineMappingExtensions.cs
+
+
+ Configuration\Inline\WhenConfiguringCallbacksInline.cs
+
+
+ Configuration\Inline\WhenConfiguringConstructorDataSourcesInline.cs
+
+
+ Configuration\Inline\WhenConfiguringDataSourcesInline.cs
+
+
+ Configuration\Inline\WhenConfiguringDataSourcesInlineIncorrectly.cs
+
+
+ Configuration\Inline\WhenConfiguringDerivedTypesInline.cs
+
+
+ Configuration\Inline\WhenConfiguringEntityMappingInline.cs
+
+
+ Configuration\Inline\WhenConfiguringEnumMappingInline.cs
+
+
+ Configuration\Inline\WhenConfiguringNameMatchingInline.cs
+
+
+ Configuration\Inline\WhenConfiguringObjectCreationInline.cs
+
+
+ Configuration\Inline\WhenConfiguringObjectTrackingInline.cs
+
+
+ Configuration\Inline\WhenConfiguringStringFormattingInline.cs
+
+
+ Configuration\Inline\WhenConfiguringTypeIdentifiersInline.cs
+
+
+ Configuration\Inline\WhenIgnoringMembersInline.cs
+
+
+ Configuration\Inline\WhenIgnoringMembersInlineIncorrectly.cs
+
+
+ Configuration\Inline\WhenMappingToNullInline.cs
+
+
+ Configuration\Inline\WhenValidatingMappingsInline.cs
+
+
+ Configuration\Inline\WhenViewingMappingPlans.cs
+
+
+ Configuration\WhenApplyingMapperConfigurations.cs
+
+
+ Configuration\WhenApplyingMapperConfigurationsIncorrectly.cs
+
+
+ Configuration\WhenConfiguringConstructorDataSources.cs
+
+
+ Configuration\WhenConfiguringDataSources.cs
+
+
+ Configuration\WhenConfiguringDataSourcesIncorrectly.cs
+
+
+ Configuration\WhenConfiguringDerivedTypes.cs
+
+
+ Configuration\WhenConfiguringDerivedTypesIncorrectly.cs
+
+
+ Configuration\WhenConfiguringEntityMapping.cs
+
+
+ Configuration\WhenConfiguringEnumMapping.cs
+
+
+ Configuration\WhenConfiguringExceptionHandling.cs
+
+
+ Configuration\WhenConfiguringMappingCallbacks.cs
+
+
+ Configuration\WhenConfiguringNameMatching.cs
+
+
+ Configuration\WhenConfiguringObjectCreation.cs
+
+
+ Configuration\WhenConfiguringObjectCreationCallbacks.cs
+
+
+ Configuration\WhenConfiguringObjectTracking.cs
+
+
+ Configuration\WhenConfiguringObjectTrackingIncorrectly.cs
+
+
+ Configuration\WhenConfiguringReverseDataSources.cs
+
+
+ Configuration\WhenConfiguringReverseDataSourcesIncorrectly.cs
+
+
+ Configuration\WhenConfiguringStringFormatting.cs
+
+
+ Configuration\WhenConfiguringTypeIdentifiers.cs
+
+
+ Configuration\WhenIgnoringMembers.cs
+
+
+ Configuration\WhenIgnoringMembersByFilter.cs
+
+
+ Configuration\WhenIgnoringMembersByGlobalFilter.cs
+
+
+ Configuration\WhenIgnoringMembersIncorrectly.cs
+
+
+ Configuration\WhenMappingToNull.cs
+
+
+ Configuration\WhenResolvingServices.cs
+
+
+ Configuration\WhenViewingMappingPlans.cs
+
+
+ Dictionaries\Configuration\WhenConfiguringDictionaryMappingIncorrectly.cs
+
+
+ Dictionaries\Configuration\WhenConfiguringNestedDictionaryMapping.cs
+
+
+ Dictionaries\Configuration\WhenConfiguringSourceDictionaryMapping.cs
+
+
+ Dictionaries\Configuration\WhenConfiguringTargetDictionaryMapping.cs
+
+
+ Dictionaries\WhenCreatingRootDictionaryMembers.cs
+
+
+ Dictionaries\WhenFlatteningToDictionaries.cs
+
+
+ Dictionaries\WhenMappingFromDictionariesOnToComplexTypes.cs
+
+
+ Dictionaries\WhenMappingFromDictionariesOnToEnumerableMembers.cs
+
+
+ Dictionaries\WhenMappingFromDictionariesOverComplexTypes.cs
+
+
+ Dictionaries\WhenMappingFromDictionariesToNewComplexTypeMembers.cs
+
+
+ Dictionaries\WhenMappingFromDictionariesToNewComplexTypes.cs
+
+
+ Dictionaries\WhenMappingFromDictionariesToNewEnumerableMembers.cs
+
+
+ Dictionaries\WhenMappingFromDictionariesToNewEnumerables.cs
+
+
+ Dictionaries\WhenMappingFromDictionaryMembers.cs
+
+
+ Dictionaries\WhenMappingOnToDictionaries.cs
+
+
+ Dictionaries\WhenMappingOnToDictionaryMembers.cs
+
+
+ Dictionaries\WhenMappingOverDictionaries.cs
+
+
+ Dictionaries\WhenMappingOverDictionaryMembers.cs
+
+
+ Dictionaries\WhenMappingToNewDictionaries.cs
+
+
+ Dictionaries\WhenMappingToNewDictionaryMembers.cs
+
+
+ Dictionaries\WhenUnflatteningFromDictionaries.cs
+
+
+ Dictionaries\WhenViewingDictionaryMappingPlans.cs
+
+
+ Extensions\Internal\WhenEquatingExpressions.cs
+
+
+ Extensions\Internal\WhenGeneratingVariableNames.cs
+
+
+ Extensions\WhenFlatteningToQueryStringViaExtensionMethods.cs
+
+
+ Extensions\WhenFlatteningViaExtensionMethods.cs
+
+
+ Extensions\WhenMappingViaExtensionMethods.cs
+
+
+ Extensions\WhenUnflatteningFromQueryStringsViaExtensionMethods.cs
+
+
+ Extensions\WhenUnflatteningViaExtensionMethods.cs
+
+
+ MapperCloning\WhenCloningConstructorDataSources.cs
+
+
+ MapperCloning\WhenCloningDataSources.cs
+
+
+ MapperCloning\WhenCloningDictionarySettings.cs
+
+
+ MapperCloning\WhenCloningMemberIgnores.cs
+
+
+ MapperCloning\WhenCloningObjectFactories.cs
+
+
+ MapperCloning\WhenCloningStringFormatting.cs
+
+
+ Members\MemberTestsBase.cs
+
+
+ Members\WhenCreatingTargetMembersFromExpressions.cs
+
+
+ Members\WhenDeterminingATypeIdentifier.cs
+
+
+ Members\WhenDeterminingRecursion.cs
+
+
+ Members\WhenFindingDataSources.cs
+
+
+ Members\WhenFindingSourceMembers.cs
+
+
+ Members\WhenFindingTargetMembers.cs
+
+
+ Members\WhenMatchingSourceToTargetMembers.cs
+
+
+ Properties\AssemblyInfo.cs
+
+
+ Reflection\WhenAccessingTypeInformation.cs
+
+
+ SimpleTypeConversion\WhenConvertingToBools.cs
+
+
+ SimpleTypeConversion\WhenConvertingToBytes.cs
+
+
+ SimpleTypeConversion\WhenConvertingToCharacters.cs
+
+
+ SimpleTypeConversion\WhenConvertingToDateTimes.cs
+
+
+ SimpleTypeConversion\WhenConvertingToDecimals.cs
+
+
+ SimpleTypeConversion\WhenConvertingToDoubles.cs
+
+
+ SimpleTypeConversion\WhenConvertingToEnums.cs
+
+
+ SimpleTypeConversion\WhenConvertingToFlagsEnums.cs
+
+
+ SimpleTypeConversion\WhenConvertingToGuids.cs
+
+
+ SimpleTypeConversion\WhenConvertingToInts.cs
+
+
+ SimpleTypeConversion\WhenConvertingToLongs.cs
+
+
+ SimpleTypeConversion\WhenConvertingToShorts.cs
+
+
+ SimpleTypeConversion\WhenConvertingToStrings.cs
+
+
+ Structs\Configuration\WhenConfiguringStructCreationCallbacks.cs
+
+
+ Structs\Configuration\WhenConfiguringStructDataSources.cs
+
+
+ Structs\Configuration\WhenConfiguringStructMappingCallbacks.cs
+
+
+ Structs\Dictionaries\WhenMappingFromDictionariesToStructs.cs
+
+
+ Structs\WhenMappingOnToStructMembers.cs
+
+
+ Structs\WhenMappingOnToStructs.cs
+
+
+ Structs\WhenMappingOverStructMembers.cs
+
+
+ Structs\WhenMappingOverStructs.cs
+
+
+ Structs\WhenMappingToNewStructMembers.cs
+
+
+ Structs\WhenMappingToNewStructs.cs
+
+
+ Structs\WhenMappingToStructEnumerables.cs
+
+
+ Structs\WhenMappingToUnmappableStructMembers.cs
+
+
+ TestClasses\Address.cs
+
+
+ TestClasses\CategoryDto.cs
+
+
+ TestClasses\CategoryEntity.cs
+
+
+ TestClasses\Child.cs
+
+
+ TestClasses\Customer.cs
+
+
+ TestClasses\CustomerViewModel.cs
+
+
+ TestClasses\DtoBase.cs
+
+
+ TestClasses\Earthworm.cs
+
+
+ TestClasses\EntityBase.cs
+
+
+ TestClasses\FacebookUser.cs
+
+
+ TestClasses\InternalField.cs
+
+
+ TestClasses\IPublicInterface.cs
+
+
+ TestClasses\MegaProduct.cs
+
+
+ TestClasses\MysteryCustomer.cs
+
+
+ TestClasses\MysteryCustomerViewModel.cs
+
+
+ TestClasses\Order.cs
+
+
+ TestClasses\OrderDto.cs
+
+
+ TestClasses\OrderEntity.cs
+
+
+ TestClasses\OrderItem.cs
+
+
+ TestClasses\OrderItemDto.cs
+
+
+ TestClasses\OrderItemEntity.cs
+
+
+ TestClasses\OrderUk.cs
+
+
+ TestClasses\OrderUs.cs
+
+
+ TestClasses\Parent.cs
+
+
+ TestClasses\PaymentTypeUk.cs
+
+
+ TestClasses\PaymentTypeUs.cs
+
+
+ TestClasses\Person.cs
+
+
+ TestClasses\PersonViewModel.cs
+
+
+ TestClasses\Product.cs
+
+
+ TestClasses\ProductDto.cs
+
+
+ TestClasses\ProductDtoMega.cs
+
+
+ TestClasses\ProductEntity.cs
+
+
+ TestClasses\PublicCtor.cs
+
+
+ TestClasses\PublicCtorStruct.cs
+
+
+ TestClasses\PublicEnumerable.cs
+
+
+ TestClasses\PublicField.cs
+
+
+ TestClasses\PublicGetMethod.cs
+
+
+ TestClasses\PublicImplementation.cs
+
+
+ TestClasses\PublicIndex.cs
+
+
+ TestClasses\PublicProperty.cs
+
+
+ TestClasses\PublicPropertyStruct.cs
+
+
+ TestClasses\PublicReadOnlyField.cs
+
+
+ TestClasses\PublicReadOnlyProperty.cs
+
+
+ TestClasses\PublicSealed.cs
+
+
+ TestClasses\PublicSetMethod.cs
+
+
+ TestClasses\PublicTwoFields.cs
+
+
+ TestClasses\PublicTwoFieldsStruct.cs
+
+
+ TestClasses\PublicTwoParamCtor.cs
+
+
+ TestClasses\PublicUnconstructable.cs
+
+
+ TestClasses\PublicWriteOnlyProperty.cs
+
+
+ TestClasses\SaveOrderItemRequest.cs
+
+
+ TestClasses\SaveOrderRequest.cs
+
+
+ TestClasses\Status.cs
+
+
+ TestClasses\StringKeyedDictionary.cs
+
+
+ TestClasses\Title.cs
+
+
+ TestClasses\TitleShortlist.cs
+
+
+ TestClasses\Wedding.cs
+
+
+ TestClasses\WeddingDto.cs
+
+
+ WhenAnalysingCollections.cs
+
+
+ WhenMappingCircularReferences.cs
+
+
+ WhenMappingDerivedTypes.cs
+
+
+ WhenMappingEntities.cs
+
+
+ WhenMappingOnToComplexTypeMembers.cs
+
+
+ WhenMappingOnToComplexTypes.cs
+
+
+ WhenMappingOnToEnumerableMembers.cs
+
+
+ WhenMappingOnToEnumerables.cs
+
+
+ WhenMappingOverComplexTypeMembers.cs
+
+
+ WhenMappingOverComplexTypes.cs
+
+
+ WhenMappingOverEnumerableMembers.cs
+
+
+ WhenMappingOverEnumerables.cs
+
+
+ WhenMappingToConstructors.cs
+
+
+ WhenMappingToMetaMembers.cs
+
+
+ WhenMappingToNewComplexTypeMembers.cs
+
+
+ WhenMappingToNewComplexTypes.cs
+
+
+ WhenMappingToNewEnumerableMembers.cs
+
+
+ WhenMappingToNewEnumerables.cs
+
+
+ WhenUnflatteningFromQueryStrings.cs
+
+
+ WhenUsingFactoryMethods.cs
+
+
+ WhenValidatingMappings.cs
+
+
+ WhenViewingMappingPlans.cs
+
+
+ WhenWorkingWithQueryStrings.cs
diff --git a/AgileMapper.UnitTests/AgileMapper.UnitTests.csproj b/AgileMapper.UnitTests/AgileMapper.UnitTests.csproj
index 28d4c8701..39082fdd9 100644
--- a/AgileMapper.UnitTests/AgileMapper.UnitTests.csproj
+++ b/AgileMapper.UnitTests/AgileMapper.UnitTests.csproj
@@ -220,6 +220,7 @@
+
diff --git a/AgileMapper.UnitTests/Configuration/WhenConfiguringDataSources.cs b/AgileMapper.UnitTests/Configuration/WhenConfiguringDataSources.cs
index b03c7d7c2..e9e20dc12 100644
--- a/AgileMapper.UnitTests/Configuration/WhenConfiguringDataSources.cs
+++ b/AgileMapper.UnitTests/Configuration/WhenConfiguringDataSources.cs
@@ -177,7 +177,7 @@ public void ShouldAllowConditionTypeTestsWhenMappingFromAnInterface()
// See https://github.com/agileobjects/AgileMapper/issues/111
[Fact]
- public void ShouldConditionallyApplyAToTargetConfiguredSimpleTypeConstant()
+ public void ShouldConditionallyApplyAToTargetSimpleTypeConstant()
{
using (var mapper = Mapper.CreateNew())
{
@@ -195,7 +195,7 @@ public void ShouldConditionallyApplyAToTargetConfiguredSimpleTypeConstant()
}
[Fact]
- public void ShouldConditionallyApplyAToTargetConfiguredSimpleType()
+ public void ShouldConditionallyApplyAToTargetSimpleType()
{
using (var mapper = Mapper.CreateNew())
{
@@ -212,7 +212,7 @@ public void ShouldConditionallyApplyAToTargetConfiguredSimpleType()
}
[Fact]
- public void ShouldConditionallyApplyAToTargetConfiguredNestedSimpleTypeExpression()
+ public void ShouldConditionallyApplyAToTargetNestedSimpleTypeExpression()
{
using (var mapper = Mapper.CreateNew())
{
@@ -236,7 +236,7 @@ public void ShouldConditionallyApplyAToTargetConfiguredNestedSimpleTypeExpressio
}
[Fact]
- public void ShouldConditionallyApplyAToTargetConfiguredSimpleTypeExpressionInAComplexTypeList()
+ public void ShouldConditionallyApplyAToTargetSimpleTypeExpressionToAComplexTypeListMember()
{
using (var mapper = Mapper.CreateNew())
{
@@ -536,7 +536,7 @@ public void ShouldApplyAConfiguredExpressionToAnArray()
.From>()
.To>()
#if NETCOREAPP2_0
- .Map(ctx => ctx.Source.Value.Split(':', System.StringSplitOptions.None))
+ .Map(ctx => ctx.Source.Value.Split(':', StringSplitOptions.None))
#else
.Map(ctx => ctx.Source.Value.Split(':'))
#endif
@@ -1213,7 +1213,7 @@ public void ShouldApplyAConfiguredSourceInterfaceMember()
// See https://github.com/agileobjects/AgileMapper/issues/64
[Fact]
- public void ShouldApplyAConfiguredRootSource()
+ public void ShouldApplyAConfiguredToTargetDataSource()
{
using (var mapper = Mapper.CreateNew())
{
@@ -1235,7 +1235,7 @@ public void ShouldApplyAConfiguredRootSource()
}
[Fact]
- public void ShouldApplyANestedOverwriteConfiguredRootSource()
+ public void ShouldApplyANestedOverwriteConfiguredToTargetDataSource()
{
using (var mapper = Mapper.CreateNew())
{
@@ -1395,7 +1395,7 @@ public void ShouldApplyAConfiguredRootSourceToANestedMember()
}
[Fact]
- public void ShouldApplyAConfiguredRootSourceToAnEnumerableElement()
+ public void ShouldApplyAToTargetComplexTypeToAComplexTypeEnumerableElement()
{
using (var mapper = Mapper.CreateNew())
{
@@ -1426,7 +1426,7 @@ public void ShouldApplyAConfiguredRootSourceToAnEnumerableElement()
}
[Fact]
- public void ShouldApplyAConfiguredEnumerableRootSource()
+ public void ShouldApplyAToTargetComplexTypeEnumerable()
{
using (var mapper = Mapper.CreateNew())
{
@@ -1463,7 +1463,7 @@ public void ShouldApplyAConfiguredEnumerableRootSource()
}
[Fact]
- public void ShouldApplyMultipleConfiguredComplexTypeRootSources()
+ public void ShouldApplyMultipleToTargetComplexTypes()
{
using (var mapper = Mapper.CreateNew())
{
@@ -1490,7 +1490,7 @@ public void ShouldApplyMultipleConfiguredComplexTypeRootSources()
}
[Fact]
- public void ShouldApplyMultipleConfiguredEnumerableRootSources()
+ public void ShouldApplyMultipleToTargetSimpleTypeEnumerables()
{
using (var mapper = Mapper.CreateNew())
{
@@ -1619,6 +1619,40 @@ public void ShouldHandleDeepNestedRuntimeTypedMembersWithACachedMappingPlan()
}
}
+ [Fact]
+ public void ShouldApplyAToTargetSimpleTypeToANestedComplexTypeMember()
+ {
+ using (var mapper = Mapper.CreateNew())
+ {
+ mapper.WhenMapping
+ .From().To>()
+ .Map(ctx => PublicEnumerable.Parse(ctx.Source)).ToTarget();
+
+ mapper.GetPlanFor>().ToANew>>();
+
+ var source = new PublicField { Value = "1,2,3" };
+ var result = mapper.Map(source).ToANew>>();
+
+ result.ShouldNotBeNull();
+ result.Value.ShouldNotBeNull();
+ result.Value.ShouldBe(1, 2, 3);
+ }
+ }
+
+ [Fact]
+ public void ShouldConditionallyApplyAToTargetSimpleTypeToANestedComplexTypeMember()
+ {
+ using (var mapper = Mapper.CreateNew())
+ {
+ mapper.WhenMapping
+ .From().To>()
+ .If(cxt => cxt.Source.Contains(','))
+ .Map(ctx => PublicEnumerable.Parse(ctx.Source)).ToTarget();
+
+ mapper.GetPlanFor>().ToANew>>();
+ }
+ }
+
#region Helper Classes
internal class IdTester
diff --git a/AgileMapper.UnitTests/Members/WhenFindingDataSources.cs b/AgileMapper.UnitTests/Members/WhenFindingDataSources.cs
index 0057b8f72..c2f20b8d1 100644
--- a/AgileMapper.UnitTests/Members/WhenFindingDataSources.cs
+++ b/AgileMapper.UnitTests/Members/WhenFindingDataSources.cs
@@ -53,7 +53,7 @@ private IQualifiedMember GetMatchingSourceMember(
var childMapperData = new ChildMemberMapperData(targetMember, rootMapperData);
var childMappingContext = rootMappingData.GetChildMappingData(childMapperData);
- return SourceMemberMatcher.GetMatchFor(childMappingContext, out _);
+ return SourceMemberMatcher.GetMatchFor(childMappingContext).SourceMember;
}
#region Helper Classes
diff --git a/AgileMapper.UnitTests/TestClasses/PublicEnumerable.cs b/AgileMapper.UnitTests/TestClasses/PublicEnumerable.cs
new file mode 100644
index 000000000..f8d385787
--- /dev/null
+++ b/AgileMapper.UnitTests/TestClasses/PublicEnumerable.cs
@@ -0,0 +1,34 @@
+namespace AgileObjects.AgileMapper.UnitTests.TestClasses
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Linq;
+
+ internal class PublicEnumerable : IEnumerable
+ {
+ private readonly List _items;
+
+ public PublicEnumerable()
+ : this(new List())
+ {
+ }
+
+ private PublicEnumerable(List items)
+ {
+ _items = items;
+ }
+
+ public static PublicEnumerable Parse(string values)
+ {
+ return new PublicEnumerable(values
+ .Split(',')
+ .Select(v => (T)Convert.ChangeType(v, typeof(T)))
+ .ToList());
+ }
+
+ public IEnumerator GetEnumerator() => _items.GetEnumerator();
+
+ IEnumerator IEnumerable.GetEnumerator() => _items.GetEnumerator();
+ }
+}
\ No newline at end of file
diff --git a/AgileMapper/Api/Configuration/CustomDataSourceTargetMemberSpecifier.cs b/AgileMapper/Api/Configuration/CustomDataSourceTargetMemberSpecifier.cs
index aba1e77f6..4eb2ed3b5 100644
--- a/AgileMapper/Api/Configuration/CustomDataSourceTargetMemberSpecifier.cs
+++ b/AgileMapper/Api/Configuration/CustomDataSourceTargetMemberSpecifier.cs
@@ -116,16 +116,16 @@ private void ThrowIfRedundantSourceMember(ConfiguredLambdaInfo valueLambdaInfo,
var targetMemberMapperData = new ChildMemberMapperData(targetMember, mappingData.MapperData);
var targetMemberMappingData = mappingData.GetChildMappingData(targetMemberMapperData);
- var bestMatchingSourceMember = SourceMemberMatcher.GetMatchFor(targetMemberMappingData, out _);
+ var bestSourceMemberMatch = SourceMemberMatcher.GetMatchFor(targetMemberMappingData);
- if (bestMatchingSourceMember == null)
+ if (!bestSourceMemberMatch.IsUseable)
{
return;
}
var sourceMember = sourceMemberLambda.ToSourceMember(MapperContext);
- if (!bestMatchingSourceMember.Matches(sourceMember))
+ if (!bestSourceMemberMatch.SourceMember.Matches(sourceMember))
{
return;
}
diff --git a/AgileMapper/Configuration/Inline/InlineMapperContextSet.cs b/AgileMapper/Configuration/Inline/InlineMapperContextSet.cs
index b87004884..2b880d6a2 100644
--- a/AgileMapper/Configuration/Inline/InlineMapperContextSet.cs
+++ b/AgileMapper/Configuration/Inline/InlineMapperContextSet.cs
@@ -3,14 +3,10 @@
using System;
using System.Collections;
using System.Collections.Generic;
-#if NET35
- using System.Linq;
-#endif
using System.Linq.Expressions;
using Api.Configuration;
using Api.Configuration.Projection;
using Caching;
- using Extensions;
#if NET35
using Extensions.Internal;
#endif
diff --git a/AgileMapper/Configuration/ParametersSwapper.cs b/AgileMapper/Configuration/ParametersSwapper.cs
index 88e1c8507..45d657d4b 100644
--- a/AgileMapper/Configuration/ParametersSwapper.cs
+++ b/AgileMapper/Configuration/ParametersSwapper.cs
@@ -3,16 +3,16 @@ namespace AgileObjects.AgileMapper.Configuration
using System;
using System.Collections.Generic;
using System.Linq;
- using Extensions;
- using Extensions.Internal;
- using Members;
- using NetStandardPolyfills;
- using ObjectPopulation;
#if NET35
using Microsoft.Scripting.Ast;
#else
using System.Linq.Expressions;
#endif
+ using Extensions;
+ using Extensions.Internal;
+ using Members;
+ using NetStandardPolyfills;
+ using ObjectPopulation;
using static Members.Member;
internal class ParametersSwapper
@@ -170,7 +170,7 @@ private static Expression ReplaceParameters(
private static MappingContextInfo GetAppropriateMappingContext(SwapArgs swapArgs)
{
- if (swapArgs.ContextTypes.All(t => t.IsSimple()))
+ if (swapArgs.SourceType.IsSimple())
{
return GetSimpleTypesMappingContextInfo(swapArgs);
}
@@ -298,8 +298,8 @@ public MappingContextInfo(SwapArgs swapArgs, Expression contextAccess)
: this(
swapArgs,
contextAccess,
- GetValueAccess(swapArgs.GetSourceAccess(contextAccess), swapArgs.ContextTypes[0]),
- GetValueAccess(swapArgs.GetTargetAccess(contextAccess), swapArgs.ContextTypes[1]))
+ GetValueAccess(swapArgs.GetSourceAccess(contextAccess), swapArgs.SourceType),
+ GetValueAccess(swapArgs.GetTargetAccess(contextAccess), swapArgs.TargetType))
{
}
@@ -370,6 +370,10 @@ public SwapArgs(
public Type[] ContextTypes { get; }
+ public Type SourceType => ContextTypes[0];
+
+ public Type TargetType => ContextTypes[1];
+
public IMemberMapperData MapperData { get; }
public Func TargetValueFactory { get; }
@@ -386,10 +390,10 @@ public Expression GetTypedContextAccess(Expression contextAccess)
=> MapperData.GetTypedContextAccess(contextAccess, ContextTypes);
public Expression GetSourceAccess(Expression contextAccess)
- => MapperData.GetSourceAccess(contextAccess, ContextTypes[0]);
+ => MapperData.GetSourceAccess(contextAccess, SourceType);
public Expression GetTargetAccess(Expression contextAccess)
- => TargetValueFactory.Invoke(MapperData, contextAccess, ContextTypes[1]);
+ => TargetValueFactory.Invoke(MapperData, contextAccess, TargetType);
}
#endregion
diff --git a/AgileMapper/DataSources/AdHocDataSource.cs b/AgileMapper/DataSources/AdHocDataSource.cs
index ecdcd95ef..65089290f 100644
--- a/AgileMapper/DataSources/AdHocDataSource.cs
+++ b/AgileMapper/DataSources/AdHocDataSource.cs
@@ -1,12 +1,12 @@
namespace AgileObjects.AgileMapper.DataSources
{
using System.Collections.Generic;
- using Members;
#if NET35
using Microsoft.Scripting.Ast;
#else
using System.Linq.Expressions;
#endif
+ using Members;
internal class AdHocDataSource : DataSourceBase
{
diff --git a/AgileMapper/DataSources/Finders/DataSourceFindContext.cs b/AgileMapper/DataSources/Finders/DataSourceFindContext.cs
index 27c0a0a01..5103d28cd 100644
--- a/AgileMapper/DataSources/Finders/DataSourceFindContext.cs
+++ b/AgileMapper/DataSources/Finders/DataSourceFindContext.cs
@@ -26,18 +26,15 @@ public DataSourceFindContext(IChildMemberMappingData childMappingData)
GetConfiguredDataSources(originalChildMapperData));
}
- private IList GetConfiguredDataSources(IMemberMapperData mapperData)
- {
- return MapperData
- .MapperContext
- .UserConfigurations
- .GetDataSources(mapperData);
- }
+ private IList GetConfiguredDataSources(IMemberMapperData mapperData)
+ => MapperContext.UserConfigurations.GetDataSources(mapperData);
public IChildMemberMappingData ChildMappingData { get; }
public IMemberMapperData MapperData => ChildMappingData.MapperData;
+ public MapperContext MapperContext => MapperData.MapperContext;
+
public int DataSourceIndex { get; set; }
public bool StopFind { get; set; }
@@ -59,7 +56,7 @@ public IDataSource GetFinalDataSource(IDataSource foundDataSource, IChildMemberM
return new ComplexTypeMappingDataSource(foundDataSource, DataSourceIndex, mappingData);
}
- if (childTargetMember.IsEnumerable)
+ if (childTargetMember.IsEnumerable && foundDataSource.SourceMember.IsEnumerable)
{
return new EnumerableMappingDataSource(foundDataSource, DataSourceIndex, mappingData);
}
diff --git a/AgileMapper/DataSources/Finders/MetaMemberDataSourceFinder.cs b/AgileMapper/DataSources/Finders/MetaMemberDataSourceFinder.cs
index e581cf8d3..8d0421445 100644
--- a/AgileMapper/DataSources/Finders/MetaMemberDataSourceFinder.cs
+++ b/AgileMapper/DataSources/Finders/MetaMemberDataSourceFinder.cs
@@ -214,16 +214,17 @@ private static bool TryGetMetaMember(
var memberMappingData = currentMappingData.GetChildMappingData(childMemberMapperData);
- currentSourceMember = SourceMemberMatcher.GetMatchFor(
+ var currentSourceMemberMatch = SourceMemberMatcher.GetMatchFor(
memberMappingData,
- out _,
searchParentContexts: false);
- if (currentSourceMember == null)
+ if (!currentSourceMemberMatch.IsUseable)
{
return false;
}
+ currentSourceMember = currentSourceMemberMatch.SourceMember;
+
currentMemberPart = new SourceMemberMetaMemberPart(
currentSourceMember,
currentMapperData,
diff --git a/AgileMapper/DataSources/Finders/SourceMemberDataSourceFinder.cs b/AgileMapper/DataSources/Finders/SourceMemberDataSourceFinder.cs
index 18aec53a3..0ec0b02da 100644
--- a/AgileMapper/DataSources/Finders/SourceMemberDataSourceFinder.cs
+++ b/AgileMapper/DataSources/Finders/SourceMemberDataSourceFinder.cs
@@ -1,8 +1,8 @@
namespace AgileObjects.AgileMapper.DataSources.Finders
{
+ using System.Collections.Generic;
using Extensions.Internal;
using Members;
- using System.Collections.Generic;
internal struct SourceMemberDataSourceFinder : IDataSourceFinder
{
@@ -13,11 +13,11 @@ public IEnumerable FindFor(DataSourceFindContext context)
yield break;
}
- var matchingSourceMemberDataSource = GetSourceMemberDataSourceOrNull(context);
+ var matchingSourceMemberDataSource = GetSourceMemberDataSource(context, out var hasUseableSourceMember);
var configuredDataSources = context.ConfiguredDataSources;
var targetMember = context.MapperData.TargetMember;
- if ((matchingSourceMemberDataSource == null) ||
+ if (!hasUseableSourceMember ||
configuredDataSources.Any(cds => cds.IsSameAs(matchingSourceMemberDataSource)))
{
if (context.DataSourceIndex == 0)
@@ -32,7 +32,10 @@ public IEnumerable FindFor(DataSourceFindContext context)
yield return context.GetFallbackDataSource();
}
- yield break;
+ if (matchingSourceMemberDataSource.SourceMember == null)
+ {
+ yield break;
+ }
}
if (matchingSourceMemberDataSource.SourceMember.IsSimple &&
@@ -65,21 +68,23 @@ public IEnumerable FindFor(DataSourceFindContext context)
}
}
- private static IDataSource GetSourceMemberDataSourceOrNull(DataSourceFindContext context)
+ private static IDataSource GetSourceMemberDataSource(
+ DataSourceFindContext context,
+ out bool hasUseableSourceMember)
{
- var bestMatchingSourceMember = SourceMemberMatcher.GetMatchFor(
- context.ChildMappingData,
- out var contextMappingData);
+ var bestSourceMemberMatch = SourceMemberMatcher.GetMatchFor(context.ChildMappingData);
+ hasUseableSourceMember = bestSourceMemberMatch.IsUseable;
- if (bestMatchingSourceMember == null)
+ if (hasUseableSourceMember)
{
- return null;
+ return context.GetFinalDataSource(
+ bestSourceMemberMatch.CreateDataSource(),
+ bestSourceMemberMatch.ContextMappingData);
}
- var sourceMemberDataSource = SourceMemberDataSource
- .For(bestMatchingSourceMember, contextMappingData.MapperData);
-
- return context.GetFinalDataSource(sourceMemberDataSource, contextMappingData);
+ return new AdHocDataSource(
+ bestSourceMemberMatch.SourceMember,
+ Constants.EmptyExpression);
}
private static bool UseFallbackComplexTypeMappingDataSource(QualifiedMember targetMember)
diff --git a/AgileMapper/DataSources/IDataSource.cs b/AgileMapper/DataSources/IDataSource.cs
index f343b67ee..218c1249b 100644
--- a/AgileMapper/DataSources/IDataSource.cs
+++ b/AgileMapper/DataSources/IDataSource.cs
@@ -1,13 +1,13 @@
namespace AgileObjects.AgileMapper.DataSources
{
using System.Collections.Generic;
- using Extensions.Internal;
- using Members;
#if NET35
using Microsoft.Scripting.Ast;
#else
using System.Linq.Expressions;
#endif
+ using Extensions.Internal;
+ using Members;
internal interface IDataSource : IConditionallyChainable
{
diff --git a/AgileMapper/DataSources/SourceMemberDataSource.cs b/AgileMapper/DataSources/SourceMemberDataSource.cs
index 823e734ad..7d0cefc3d 100644
--- a/AgileMapper/DataSources/SourceMemberDataSource.cs
+++ b/AgileMapper/DataSources/SourceMemberDataSource.cs
@@ -13,7 +13,7 @@
internal class SourceMemberDataSource : DataSourceBase
{
- private SourceMemberDataSource(
+ public SourceMemberDataSource(
IQualifiedMember sourceMember,
Expression sourceMemberValue,
IMemberMapperData mapperData)
@@ -63,18 +63,5 @@ private static Expression GetRuntimeTypeCheck(UnaryExpression cast, IMemberMappe
return memberHasRuntimeType;
}
-
- public static SourceMemberDataSource For(IQualifiedMember sourceMember, IMemberMapperData mapperData)
- {
- sourceMember = sourceMember.RelativeTo(mapperData.SourceMember);
-
- var sourceMemberValue = sourceMember
- .GetQualifiedAccess(mapperData)
- .GetConversionTo(sourceMember.Type);
-
- var sourceMemberDataSource = new SourceMemberDataSource(sourceMember, sourceMemberValue, mapperData);
-
- return sourceMemberDataSource;
- }
}
}
\ No newline at end of file
diff --git a/AgileMapper/Members/SourceMemberMatch.cs b/AgileMapper/Members/SourceMemberMatch.cs
new file mode 100644
index 000000000..29d387ff9
--- /dev/null
+++ b/AgileMapper/Members/SourceMemberMatch.cs
@@ -0,0 +1,62 @@
+namespace AgileObjects.AgileMapper.Members
+{
+#if NET35
+ using Microsoft.Scripting.Ast;
+#else
+ using System.Linq.Expressions;
+#endif
+ using DataSources;
+ using Extensions.Internal;
+
+ internal class SourceMemberMatch
+ {
+ public static readonly SourceMemberMatch Null = new SourceMemberMatch();
+
+ private SourceMemberMatch()
+ {
+ }
+
+ public SourceMemberMatch(
+ IQualifiedMember sourceMember,
+ IChildMemberMappingData contextMappingData,
+ bool isUseable = true)
+ {
+ SourceMember = GetFinalSourceMember(sourceMember, contextMappingData.MapperData);
+ ContextMappingData = contextMappingData;
+ IsUseable = isUseable;
+ }
+
+ private static IQualifiedMember GetFinalSourceMember(
+ IQualifiedMember sourceMember,
+ IMemberMapperData targetMapperData)
+ {
+ return targetMapperData
+ .MapperContext
+ .QualifiedMemberFactory
+ .GetFinalSourceMember(sourceMember, targetMapperData.TargetMember);
+ }
+
+ public IQualifiedMember SourceMember { get; }
+
+ public IChildMemberMappingData ContextMappingData { get; }
+
+ public bool IsUseable { get; }
+
+ public IDataSource CreateDataSource()
+ {
+ var mapperData = ContextMappingData.MapperData;
+ var sourceMember = SourceMember.RelativeTo(mapperData.SourceMember);
+
+ var sourceMemberValue = sourceMember
+ .GetQualifiedAccess(mapperData)
+ .GetConversionTo(sourceMember.Type);
+
+ var sourceMemberDataSource = new SourceMemberDataSource(
+ sourceMember,
+ sourceMemberValue,
+ mapperData);
+
+ return sourceMemberDataSource;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AgileMapper/Members/SourceMemberMatcher.cs b/AgileMapper/Members/SourceMemberMatcher.cs
index fa5e0a1d2..617953892 100644
--- a/AgileMapper/Members/SourceMemberMatcher.cs
+++ b/AgileMapper/Members/SourceMemberMatcher.cs
@@ -4,90 +4,65 @@
using System.Collections.Generic;
using System.Linq;
using Extensions;
+ using NetStandardPolyfills;
internal static class SourceMemberMatcher
{
- public static IQualifiedMember GetMatchFor(
- IChildMemberMappingData targetData,
- out IChildMemberMappingData contextMappingData,
+ public static SourceMemberMatch GetMatchFor(
+ IChildMemberMappingData targetMappingData,
bool searchParentContexts = true)
{
- var parentSourceMember = targetData.MapperData.SourceMember;
+ var parentSourceMember = targetMappingData.MapperData.SourceMember;
if (parentSourceMember.IsSimple)
{
- contextMappingData = null;
- return null;
- }
-
- if (ExactMatchingSourceMemberExists(parentSourceMember, targetData, out var matchingMember))
- {
- contextMappingData = targetData;
- return GetFinalSourceMember(matchingMember, targetData);
+ return SourceMemberMatch.Null;
}
- matchingMember = EnumerateSourceMembers(parentSourceMember, targetData)
- .FirstOrDefault(sm => IsMatchingMember(sm, targetData.MapperData));
-
- if (matchingMember != null)
+ if (ExactMatchingMemberExists(parentSourceMember, targetMappingData, out var matchingMember) &&
+ TypesAreCompatible(matchingMember.Type, targetMappingData.MapperData))
{
- contextMappingData = targetData;
- return GetFinalSourceMember(matchingMember, targetData);
+ return new SourceMemberMatch(matchingMember, targetMappingData);
}
- if (searchParentContexts)
+ if (TryFindSourceMemberMatch(
+ targetMappingData,
+ parentSourceMember,
+ ref matchingMember,
+ out var sourceMemberMatch))
{
- return GetParentContextMatchOrNull(targetData, out contextMappingData);
+ return sourceMemberMatch;
}
- contextMappingData = null;
- return null;
- }
-
- private static IQualifiedMember GetParentContextMatchOrNull(
- IChildMemberMappingData targetData,
- out IChildMemberMappingData contextMappingData)
- {
- var mappingData = targetData.Parent;
-
- while (mappingData.Parent != null)
+ if (searchParentContexts &&
+ TryFindParentContextSourceMemberMatch(targetMappingData, ref matchingMember, out sourceMemberMatch))
{
- if (mappingData.MapperData.IsEntryPoint ||
- mappingData.MapperData.TargetMemberIsEnumerableElement())
- {
- break;
- }
-
- mappingData = mappingData.Parent;
-
- var childMapperData = new ChildMemberMapperData(targetData.MapperData.TargetMember, mappingData.MapperData);
- contextMappingData = mappingData.GetChildMappingData(childMapperData);
-
- var matchingMember = EnumerateSourceMembers(mappingData.MapperData.SourceMember, contextMappingData)
- .FirstOrDefault(sm => IsMatchingMember(sm, targetData.MapperData));
-
- if (matchingMember != null)
- {
- return GetFinalSourceMember(matchingMember, targetData);
- }
+ return sourceMemberMatch;
}
- contextMappingData = null;
- return null;
+ return (matchingMember != null)
+ ? new SourceMemberMatch(matchingMember, targetMappingData, isUseable: false)
+ : SourceMemberMatch.Null;
}
- private static bool ExactMatchingSourceMemberExists(
+ private static bool ExactMatchingMemberExists(
IQualifiedMember parentSourceMember,
IChildMemberMappingData targetData,
out IQualifiedMember matchingMember)
{
+ var mapperData = targetData.MapperData;
+
+ var matcher = mapperData.TargetType.IsAssignableTo(mapperData.SourceType)
+ ? (Func)MembersAreTheSame
+ : MembersMatch;
+
var sourceMember = QuerySourceMembers(
parentSourceMember,
targetData,
- MembersMatch)
+ matcher)
.FirstOrDefault();
- if ((sourceMember == null) || !TypesAreCompatible(sourceMember.Type, targetData.MapperData))
+ if (sourceMember == null)
{
matchingMember = null;
return false;
@@ -97,9 +72,12 @@ private static bool ExactMatchingSourceMemberExists(
return true;
}
+ private static bool MembersAreTheSame(IChildMemberMappingData mappingData, Member sourceMember)
+ => mappingData.MapperData.TargetMember.LeafMember.Equals(sourceMember);
+
private static bool MembersMatch(IChildMemberMappingData mappingData, Member sourceMember)
{
- if (mappingData.MapperData.TargetMember.LeafMember.Equals(sourceMember))
+ if (MembersAreTheSame(mappingData, sourceMember))
{
return true;
}
@@ -127,15 +105,82 @@ private static IEnumerable QuerySourceMembers(
: members.Filter(m => m.MemberType != MemberType.GetMethod);
}
- private static IQualifiedMember GetFinalSourceMember(
- IQualifiedMember sourceMember,
- IChildMemberMappingData targetData)
+ private static bool TryFindParentContextSourceMemberMatch(
+ IChildMemberMappingData targetMappingData,
+ ref IQualifiedMember matchingMember,
+ out SourceMemberMatch sourceMemberMatch)
{
- return targetData
- .MapperData
- .MapperContext
- .QualifiedMemberFactory
- .GetFinalSourceMember(sourceMember, targetData.MapperData.TargetMember);
+ var targetMember = targetMappingData.MapperData.TargetMember;
+ var mappingData = targetMappingData.Parent;
+
+ while (mappingData.Parent != null)
+ {
+ if (mappingData.MapperData.IsEntryPoint ||
+ mappingData.MapperData.TargetMemberIsEnumerableElement())
+ {
+ break;
+ }
+
+ mappingData = mappingData.Parent;
+
+ var childMapperData = new ChildMemberMapperData(targetMember, mappingData.MapperData);
+ var contextMappingData = mappingData.GetChildMappingData(childMapperData);
+
+ if (TryFindSourceMemberMatch(
+ targetMappingData,
+ mappingData.MapperData.SourceMember,
+ contextMappingData,
+ ref matchingMember,
+ out sourceMemberMatch))
+ {
+ return true;
+ }
+ }
+
+ sourceMemberMatch = null;
+ return false;
+ }
+
+ private static bool TryFindSourceMemberMatch(
+ IChildMemberMappingData targetMappingData,
+ IQualifiedMember parentSourceMember,
+ ref IQualifiedMember matchingMember,
+ out SourceMemberMatch sourceMemberMatch)
+ {
+ return TryFindSourceMemberMatch(
+ targetMappingData,
+ parentSourceMember,
+ targetMappingData,
+ ref matchingMember,
+ out sourceMemberMatch);
+ }
+
+ private static bool TryFindSourceMemberMatch(
+ IChildMemberMappingData targetMappingData,
+ IQualifiedMember parentSourceMember,
+ IChildMemberMappingData contextMappingData,
+ ref IQualifiedMember matchingMember,
+ out SourceMemberMatch sourceMemberMatch)
+ {
+ var candidateSourceMembers = EnumerateSourceMembers(parentSourceMember, contextMappingData)
+ .Where(targetMappingData.MapperData.TargetMember.Matches);
+
+ foreach (var sourceMember in candidateSourceMembers)
+ {
+ if (TypesAreCompatible(sourceMember.Type, targetMappingData.MapperData))
+ {
+ sourceMemberMatch = new SourceMemberMatch(sourceMember, contextMappingData);
+ return true;
+ }
+
+ if (matchingMember == null)
+ {
+ matchingMember = sourceMember;
+ }
+ }
+
+ sourceMemberMatch = null;
+ return false;
}
private static IEnumerable EnumerateSourceMembers(
@@ -201,9 +246,6 @@ private static bool MembersHaveCompatibleTypes(IChildMemberMappingData rootData,
return targetMember.Type == typeof(object);
}
- private static bool IsMatchingMember(IQualifiedMember sourceMember, IMemberMapperData mapperData)
- => mapperData.TargetMember.Matches(sourceMember) && TypesAreCompatible(sourceMember.Type, mapperData);
-
private static bool TypesAreCompatible(Type sourceType, IMemberMapperData mapperData)
=> mapperData.CanConvert(sourceType, mapperData.TargetMember.Type);
}
diff --git a/AgileMapper/ObjectPopulation/ObjectMapperData.cs b/AgileMapper/ObjectPopulation/ObjectMapperData.cs
index b046f0954..fc755e267 100644
--- a/AgileMapper/ObjectPopulation/ObjectMapperData.cs
+++ b/AgileMapper/ObjectPopulation/ObjectMapperData.cs
@@ -5,6 +5,11 @@ namespace AgileObjects.AgileMapper.ObjectPopulation
using System.Globalization;
using System.Linq;
using System.Reflection;
+#if NET35
+ using Microsoft.Scripting.Ast;
+#else
+ using System.Linq.Expressions;
+#endif
using DataSources;
using Enumerables;
using Extensions;
@@ -14,11 +19,6 @@ namespace AgileObjects.AgileMapper.ObjectPopulation
using Members.Sources;
using NetStandardPolyfills;
using ReadableExpressions.Extensions;
-#if NET35
- using Microsoft.Scripting.Ast;
-#else
- using System.Linq.Expressions;
-#endif
using static Members.Member;
internal class ObjectMapperData : BasicMapperData, IMemberMapperData