diff --git a/AgileMapper.PerformanceTester.Net45/AgileMapper.PerformanceTester.Net45.csproj b/AgileMapper.PerformanceTester.Net45/AgileMapper.PerformanceTester.Net45.csproj
index 32e86bc86..dc1e079ff 100644
--- a/AgileMapper.PerformanceTester.Net45/AgileMapper.PerformanceTester.Net45.csproj
+++ b/AgileMapper.PerformanceTester.Net45/AgileMapper.PerformanceTester.Net45.csproj
@@ -37,8 +37,8 @@
..\packages\AgileObjects.NetStandardPolyfills.1.4.0\lib\net40\AgileObjects.NetStandardPolyfills.dll
-
- ..\packages\AgileObjects.ReadableExpressions.2.3.1\lib\net40\AgileObjects.ReadableExpressions.dll
+
+ ..\packages\AgileObjects.ReadableExpressions.2.3.2\lib\net40\AgileObjects.ReadableExpressions.dll
..\packages\AutoMapper.7.0.1\lib\net45\AutoMapper.dll
diff --git a/AgileMapper.PerformanceTester.Net45/packages.config b/AgileMapper.PerformanceTester.Net45/packages.config
index 4352c4c8d..24b54cac7 100644
--- a/AgileMapper.PerformanceTester.Net45/packages.config
+++ b/AgileMapper.PerformanceTester.Net45/packages.config
@@ -1,7 +1,7 @@
-
+
diff --git a/AgileMapper.UnitTests.Net35/AgileMapper.UnitTests.Net35.csproj b/AgileMapper.UnitTests.Net35/AgileMapper.UnitTests.Net35.csproj
index c014778c5..fec9a2f6d 100644
--- a/AgileMapper.UnitTests.Net35/AgileMapper.UnitTests.Net35.csproj
+++ b/AgileMapper.UnitTests.Net35/AgileMapper.UnitTests.Net35.csproj
@@ -37,8 +37,8 @@
..\packages\AgileObjects.NetStandardPolyfills.1.4.0\lib\net35\AgileObjects.NetStandardPolyfills.dll
-
- ..\packages\AgileObjects.ReadableExpressions.2.3.1\lib\net35\AgileObjects.ReadableExpressions.dll
+
+ ..\packages\AgileObjects.ReadableExpressions.2.3.2\lib\net35\AgileObjects.ReadableExpressions.dll
..\packages\DynamicLanguageRuntime.1.1.2\lib\Net35\Microsoft.Dynamic.dll
diff --git a/AgileMapper.UnitTests.Net35/packages.config b/AgileMapper.UnitTests.Net35/packages.config
index b15618b29..0f40009f4 100644
--- a/AgileMapper.UnitTests.Net35/packages.config
+++ b/AgileMapper.UnitTests.Net35/packages.config
@@ -1,7 +1,7 @@
-
+
diff --git a/AgileMapper.UnitTests.NonParallel/AgileMapper.UnitTests.NonParallel.csproj b/AgileMapper.UnitTests.NonParallel/AgileMapper.UnitTests.NonParallel.csproj
index 6ad7ae3be..538211964 100644
--- a/AgileMapper.UnitTests.NonParallel/AgileMapper.UnitTests.NonParallel.csproj
+++ b/AgileMapper.UnitTests.NonParallel/AgileMapper.UnitTests.NonParallel.csproj
@@ -42,8 +42,8 @@
..\packages\AgileObjects.NetStandardPolyfills.1.4.0\lib\net40\AgileObjects.NetStandardPolyfills.dll
-
- ..\packages\AgileObjects.ReadableExpressions.2.3.1\lib\net40\AgileObjects.ReadableExpressions.dll
+
+ ..\packages\AgileObjects.ReadableExpressions.2.3.2\lib\net40\AgileObjects.ReadableExpressions.dll
diff --git a/AgileMapper.UnitTests.NonParallel/packages.config b/AgileMapper.UnitTests.NonParallel/packages.config
index 2a2122151..64734ef6e 100644
--- a/AgileMapper.UnitTests.NonParallel/packages.config
+++ b/AgileMapper.UnitTests.NonParallel/packages.config
@@ -1,7 +1,7 @@
-
+
diff --git a/AgileMapper.UnitTests/AgileMapper.UnitTests.csproj b/AgileMapper.UnitTests/AgileMapper.UnitTests.csproj
index 39082fdd9..5f63268b0 100644
--- a/AgileMapper.UnitTests/AgileMapper.UnitTests.csproj
+++ b/AgileMapper.UnitTests/AgileMapper.UnitTests.csproj
@@ -44,8 +44,8 @@
..\packages\AgileObjects.NetStandardPolyfills.1.4.0\lib\net40\AgileObjects.NetStandardPolyfills.dll
-
- ..\packages\AgileObjects.ReadableExpressions.2.3.1\lib\net40\AgileObjects.ReadableExpressions.dll
+
+ ..\packages\AgileObjects.ReadableExpressions.2.3.2\lib\net40\AgileObjects.ReadableExpressions.dll
..\packages\Microsoft.Extensions.Primitives.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll
diff --git a/AgileMapper.UnitTests/packages.config b/AgileMapper.UnitTests/packages.config
index 09b6deb71..71b5a86a6 100644
--- a/AgileMapper.UnitTests/packages.config
+++ b/AgileMapper.UnitTests/packages.config
@@ -1,7 +1,7 @@
-
+
diff --git a/AgileMapper/AgileMapper.csproj b/AgileMapper/AgileMapper.csproj
index 9d09ee765..aed85a6be 100644
--- a/AgileMapper/AgileMapper.csproj
+++ b/AgileMapper/AgileMapper.csproj
@@ -30,7 +30,7 @@
-
+
diff --git a/AgileMapper/Api/Configuration/Dictionaries/DictionaryMappingConfigurator.cs b/AgileMapper/Api/Configuration/Dictionaries/DictionaryMappingConfigurator.cs
index 85ec2477b..81268fe80 100644
--- a/AgileMapper/Api/Configuration/Dictionaries/DictionaryMappingConfigurator.cs
+++ b/AgileMapper/Api/Configuration/Dictionaries/DictionaryMappingConfigurator.cs
@@ -17,12 +17,9 @@ internal class DictionaryMappingConfigurator :
ISourceDynamicTargetTypeSelector
#endif
{
- private readonly MappingConfigInfo _configInfo;
-
internal DictionaryMappingConfigurator(MappingConfigInfo configInfo)
: base(configInfo)
{
- _configInfo = configInfo;
}
#region Mapping Settings
@@ -102,24 +99,24 @@ private DictionaryMappingConfigurator RegisterElementKeyPattern(
private MappingConfigInfo GetConfigInfo(DictionaryContext context)
{
- return (_configInfo.TargetType != typeof(object))
- ? _configInfo.Copy().Set(context)
+ return (ConfigInfo.TargetType != typeof(object))
+ ? ConfigInfo.Copy().Set(context)
: GetGlobalConfigInfo(context);
}
private MappingConfigInfo GetGlobalConfigInfo(DictionaryContext context)
- => _configInfo.Copy().ForAllRuleSets().ForAllTargetTypes().Set(context);
+ => ConfigInfo.Copy().ForAllRuleSets().ForAllTargetTypes().Set(context);
#region AndWhenMapping
MappingConfigStartingPoint IGlobalDictionarySettings.AndWhenMapping
- => new MappingConfigStartingPoint(_configInfo.MapperContext);
+ => new MappingConfigStartingPoint(ConfigInfo.MapperContext);
public ISourceDictionaryTargetTypeSelector AndWhenMapping => this;
#if FEATURE_DYNAMIC
MappingConfigStartingPoint IGlobalDynamicSettings.AndWhenMapping
- => new MappingConfigStartingPoint(_configInfo.MapperContext);
+ => new MappingConfigStartingPoint(ConfigInfo.MapperContext);
ISourceDynamicTargetTypeSelector ISourceDynamicSettings.AndWhenMapping => this;
#endif
@@ -130,7 +127,7 @@ MappingConfigStartingPoint IGlobalDynamicSettings.AndWhenMapping
#region Dictionaries
public ISourceDictionaryMappingConfigurator To()
- => CreateDictionaryConfigurator(_configInfo.ForAllRuleSets());
+ => CreateDictionaryConfigurator(ConfigInfo.ForAllRuleSets());
public ISourceDictionaryMappingConfigurator ToANew()
=> CreateDictionaryConfigurator(Constants.CreateNew);
@@ -143,7 +140,7 @@ public ISourceDictionaryMappingConfigurator Over()
private SourceDictionaryMappingConfigurator CreateDictionaryConfigurator(
string ruleSetName)
- => CreateDictionaryConfigurator(_configInfo.ForRuleSet(ruleSetName));
+ => CreateDictionaryConfigurator(ConfigInfo.ForRuleSet(ruleSetName));
private static SourceDictionaryMappingConfigurator CreateDictionaryConfigurator(
MappingConfigInfo configInfo)
@@ -155,7 +152,7 @@ private static SourceDictionaryMappingConfigurator CreateDictio
#region Dynamics
ISourceDynamicMappingConfigurator ISourceDynamicTargetTypeSelector.To()
- => CreateDynamicConfigurator(_configInfo.ForAllRuleSets());
+ => CreateDynamicConfigurator(ConfigInfo.ForAllRuleSets());
ISourceDynamicMappingConfigurator ISourceDynamicTargetTypeSelector.ToANew()
=> CreateDynamicConfigurator(Constants.CreateNew);
@@ -168,7 +165,7 @@ ISourceDynamicMappingConfigurator ISourceDynamicTargetTypeSelector.Over
private SourceDynamicMappingConfigurator CreateDynamicConfigurator(
string ruleSetName)
- => CreateDynamicConfigurator(_configInfo.ForRuleSet(ruleSetName));
+ => CreateDynamicConfigurator(ConfigInfo.ForRuleSet(ruleSetName));
private static SourceDynamicMappingConfigurator CreateDynamicConfigurator(
MappingConfigInfo configInfo)
diff --git a/AgileMapper/Api/Configuration/Dictionaries/TargetDictionaryMappingConfigurator.cs b/AgileMapper/Api/Configuration/Dictionaries/TargetDictionaryMappingConfigurator.cs
index e318ae5f9..8963140f9 100644
--- a/AgileMapper/Api/Configuration/Dictionaries/TargetDictionaryMappingConfigurator.cs
+++ b/AgileMapper/Api/Configuration/Dictionaries/TargetDictionaryMappingConfigurator.cs
@@ -52,7 +52,7 @@ public ICustomTargetDictionaryKeySpecifier MapMember MapMember
private QualifiedMember GetSourceMemberOrThrow(LambdaExpression lambda)
{
- var sourceMember = lambda.Body.ToSourceMember(ConfigInfo.MapperContext);
+ var sourceMember = lambda.Body.ToSourceMember(MapperContext);
if (sourceMember != null)
{
diff --git a/AgileMapper/Api/Configuration/MappingConfigurator.cs b/AgileMapper/Api/Configuration/MappingConfigurator.cs
index 94a20e8a8..757096467 100644
--- a/AgileMapper/Api/Configuration/MappingConfigurator.cs
+++ b/AgileMapper/Api/Configuration/MappingConfigurator.cs
@@ -37,6 +37,8 @@ public MappingConfigurator(MappingConfigInfo configInfo)
protected MapperContext MapperContext => ConfigInfo.MapperContext;
+ private UserConfigurationSet UserConfigurations => MapperContext.UserConfigurations;
+
#region IFullMappingInlineConfigurator Members
public MappingConfigStartingPoint WhenMapping
@@ -96,7 +98,7 @@ public IFullProjectionInlineConfigurator RecurseToDepth(int re
{
var depthSettings = new RecursionDepthSettings(ConfigInfo, recursionDepth);
- ConfigInfo.MapperContext.UserConfigurations.Add(depthSettings);
+ UserConfigurations.Add(depthSettings);
return this;
}
@@ -213,7 +215,7 @@ private FactorySpecifier CreateFactorySpecifier PassExceptionsTo(Action> callback)
{
- MapperContext.UserConfigurations.Add(new ExceptionCallback(ConfigInfo, callback.ToConstantExpression()));
+ UserConfigurations.Add(new ExceptionCallback(ConfigInfo, callback.ToConstantExpression()));
return this;
}
@@ -223,13 +225,13 @@ public IFullMappingSettings PassExceptionsTo(Action SetMappedObjectCaching(bool cache)
{
- MapperContext.UserConfigurations.Add(new MappedObjectCachingSetting(ConfigInfo, cache));
+ UserConfigurations.Add(new MappedObjectCachingSetting(ConfigInfo, cache));
return this;
}
public IFullMappingSettings MapNullCollectionsToNull()
{
- MapperContext.UserConfigurations.Add(new NullCollectionsSetting(ConfigInfo));
+ UserConfigurations.Add(new NullCollectionsSetting(ConfigInfo));
return this;
}
@@ -239,7 +241,7 @@ public IFullMappingSettings MapNullCollectionsToNull()
private IFullMappingSettings SetEntityKeyMapping(bool mapKeys)
{
- MapperContext.UserConfigurations.Add(new EntityKeyMappingSetting(ConfigInfo, mapKeys));
+ UserConfigurations.Add(new EntityKeyMappingSetting(ConfigInfo, mapKeys));
return this;
}
@@ -251,7 +253,7 @@ public IFullMappingSettings DoNotAutoReverseConfiguredDataSour
private IFullMappingSettings SetDataSourceReversal(bool reverse)
{
- MapperContext.UserConfigurations.Add(new DataSourceReversalSetting(ConfigInfo, reverse));
+ UserConfigurations.Add(new DataSourceReversalSetting(ConfigInfo, reverse));
return this;
}
@@ -299,7 +301,7 @@ private MappingConfigContinuation IgnoreMembersByFilter(
#else
var configuredIgnoredMember = new ConfiguredIgnoredMember(ConfigInfo, memberFilter);
#endif
- MapperContext.UserConfigurations.Add(configuredIgnoredMember);
+ UserConfigurations.Add(configuredIgnoredMember);
return new MappingConfigContinuation(ConfigInfo);
}
@@ -323,7 +325,7 @@ private MappingConfigContinuation IgnoreMembers(
#else
var configuredIgnoredMember = new ConfiguredIgnoredMember(ConfigInfo, targetMember);
#endif
- MapperContext.UserConfigurations.Add(configuredIgnoredMember);
+ UserConfigurations.Add(configuredIgnoredMember);
ConfigInfo.NegateCondition();
}
@@ -461,7 +463,7 @@ private MappingConfigContinuation RegisterMapToNullCondition()
{
var condition = new MapToNullCondition(ConfigInfo);
- MapperContext.UserConfigurations.Add(condition);
+ UserConfigurations.Add(condition);
return new MappingConfigContinuation(ConfigInfo);
}
diff --git a/AgileMapper/Configuration/ConfiguredIgnoredMember.cs b/AgileMapper/Configuration/ConfiguredIgnoredMember.cs
index 7bf4c4ae1..e9fbd8189 100644
--- a/AgileMapper/Configuration/ConfiguredIgnoredMember.cs
+++ b/AgileMapper/Configuration/ConfiguredIgnoredMember.cs
@@ -1,14 +1,14 @@
namespace AgileObjects.AgileMapper.Configuration
{
using System;
- using DataSources;
- using Members;
- using ReadableExpressions;
#if NET35
using Microsoft.Scripting.Ast;
#else
using System.Linq.Expressions;
#endif
+ using DataSources;
+ using Members;
+ using ReadableExpressions;
internal class ConfiguredIgnoredMember :
UserConfiguredItemBase,
diff --git a/AgileMapper/Configuration/MappingConfigInfo.cs b/AgileMapper/Configuration/MappingConfigInfo.cs
index ee20152ba..afecc4864 100644
--- a/AgileMapper/Configuration/MappingConfigInfo.cs
+++ b/AgileMapper/Configuration/MappingConfigInfo.cs
@@ -17,7 +17,7 @@
internal class MappingConfigInfo : ITypePair
{
- private static readonly MappingRuleSet _allRuleSets = new MappingRuleSet("*", null, null, null, null, null, null);
+ private static readonly MappingRuleSet _allRuleSets = new MappingRuleSet("*");
public static readonly MappingConfigInfo AllRuleSetsSourceTypesAndTargetTypes =
AllRuleSetsAndSourceTypes(null).ForAllTargetTypes();
diff --git a/AgileMapper/Configuration/MemberSelector.cs b/AgileMapper/Configuration/MemberSelector.cs
index 13802401f..b45db9d5f 100644
--- a/AgileMapper/Configuration/MemberSelector.cs
+++ b/AgileMapper/Configuration/MemberSelector.cs
@@ -7,7 +7,7 @@ namespace AgileObjects.AgileMapper.Configuration
using NetStandardPolyfills;
///
- /// Provides a fluent interface to select members by their characteristics.
+ /// Provides a fluent interface to select target members by their characteristics.
///
public class TargetMemberSelector
{
diff --git a/AgileMapper/Constants.cs b/AgileMapper/Constants.cs
index 64462339d..d7f0161d7 100644
--- a/AgileMapper/Constants.cs
+++ b/AgileMapper/Constants.cs
@@ -3,13 +3,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
- using Extensions.Internal;
- using NetStandardPolyfills;
#if NET35
using Microsoft.Scripting.Ast;
#else
using System.Linq.Expressions;
#endif
+ using Extensions.Internal;
+ using NetStandardPolyfills;
internal static class Constants
{
@@ -23,13 +23,13 @@ internal static class Constants
public static readonly Expression EmptyExpression = Expression.Empty();
- public const string CreateNew = "CreateNew";
+ public const string CreateNew = nameof(CreateNew);
- public const string Merge = "Merge";
+ public const string Merge = nameof(Merge);
- public const string Overwrite = "Overwrite";
+ public const string Overwrite = nameof(Overwrite);
- public const string Project = "Project";
+ public const string Project = nameof(Project);
public const int BeforeLoopExitCheck = 0;
@@ -57,7 +57,7 @@ internal static class Constants
typeof(ulong)
};
- public static readonly Type[] NumericTypes = WholeNumberNumericTypes
+ public static readonly IList NumericTypes = WholeNumberNumericTypes
.Append(new[] { typeof(float), typeof(decimal), typeof(double) });
public static readonly IDictionary NumericTypeMaxValuesByType = GetValuesByType("MaxValue");
diff --git a/AgileMapper/DataSources/ConfiguredDataSource.cs b/AgileMapper/DataSources/ConfiguredDataSource.cs
index 319bfd5c7..37edb4f0e 100644
--- a/AgileMapper/DataSources/ConfiguredDataSource.cs
+++ b/AgileMapper/DataSources/ConfiguredDataSource.cs
@@ -1,12 +1,12 @@
namespace AgileObjects.AgileMapper.DataSources
{
- using Extensions.Internal;
- using Members;
#if NET35
using Microsoft.Scripting.Ast;
#else
using System.Linq.Expressions;
#endif
+ using Extensions.Internal;
+ using Members;
internal class ConfiguredDataSource : DataSourceBase, IConfiguredDataSource
{
diff --git a/AgileMapper/DataSources/DataSourceBase.cs b/AgileMapper/DataSources/DataSourceBase.cs
index dca0ee6d9..06d27f183 100644
--- a/AgileMapper/DataSources/DataSourceBase.cs
+++ b/AgileMapper/DataSources/DataSourceBase.cs
@@ -185,6 +185,8 @@ private static bool IsNotOptionalEntityMemberId(IMemberMapperData mapperData)
public bool IsConditional => Condition != null;
+ public virtual bool IsFallback => false;
+
public virtual Expression Condition { get; }
public ICollection Variables { get; }
diff --git a/AgileMapper/DataSources/DataSourceSet.cs b/AgileMapper/DataSources/DataSourceSet.cs
index b66f1a425..e52c97457 100644
--- a/AgileMapper/DataSources/DataSourceSet.cs
+++ b/AgileMapper/DataSources/DataSourceSet.cs
@@ -27,7 +27,7 @@ public DataSourceSet(IMemberMapperData mapperData, params IDataSource[] dataSour
return;
}
- var variables = new List();
+ var variables = default(List);
for (var i = 0; i < dataSources.Length;)
{
@@ -45,6 +45,11 @@ public DataSourceSet(IMemberMapperData mapperData, params IDataSource[] dataSour
if (dataSource.Variables.Any())
{
+ if (variables == null)
+ {
+ variables = new List();
+ }
+
variables.AddRange(dataSource.Variables);
}
@@ -54,7 +59,9 @@ public DataSourceSet(IMemberMapperData mapperData, params IDataSource[] dataSour
}
}
- Variables = variables;
+ Variables = (variables != null)
+ ? (IList)variables
+ : Enumerable.EmptyArray;
}
public IMemberMapperData MapperData { get; }
@@ -71,6 +78,8 @@ public DataSourceSet(IMemberMapperData mapperData, params IDataSource[] dataSour
public IDataSource this[int index] => _dataSources[index];
+ public int Count => _dataSources.Count;
+
public Expression ValueExpression => _value ?? (_value = BuildValueExpression());
private Expression BuildValueExpression()
@@ -85,7 +94,7 @@ private Expression BuildValueExpression()
var dataSourceValue = dataSource.IsConditional
? Expression.Condition(
dataSource.Condition,
- isFirstDataSource
+ isFirstDataSource
? dataSource.Value
: dataSource.Value.GetConversionTo(value.Type),
isFirstDataSource
@@ -99,67 +108,30 @@ private Expression BuildValueExpression()
return value;
}
- public Expression GetPopulationExpression()
- {
- var fallbackValue = GetFallbackValueOrNull();
- var excludeFallback = fallbackValue == null;
-
- Expression population = null;
-
- for (var i = _dataSources.Count - 1; i >= 0; --i)
- {
- var dataSource = _dataSources[i];
-
- if (i == _dataSources.Count - 1)
- {
- if (excludeFallback)
- {
- continue;
- }
-
- population = MapperData.GetTargetMemberPopulation(fallbackValue);
-
- if (dataSource.IsConditional)
- {
- population = dataSource.AddCondition(population);
- }
-
- population = dataSource.AddPreCondition(population);
- continue;
- }
-
- var memberPopulation = MapperData.GetTargetMemberPopulation(dataSource.Value);
-
- population = dataSource.AddCondition(memberPopulation, population);
- population = dataSource.AddPreCondition(population);
- }
-
- return population;
- }
-
- private Expression GetFallbackValueOrNull()
+ public Expression GetFinalValueOrNull()
{
var finalDataSource = _dataSources.Last();
- var fallbackValue = finalDataSource.Value;
+ var finalValue = finalDataSource.Value;
- if (finalDataSource.IsConditional || _dataSources.HasOne())
+ if (!finalDataSource.IsFallback)
{
- return fallbackValue;
+ return finalValue;
}
- if (fallbackValue.NodeType == ExpressionType.Coalesce)
+ if (finalValue.NodeType == ExpressionType.Coalesce)
{
- return ((BinaryExpression)fallbackValue).Right;
+ // Coalesce between the existing target member value and the fallback:
+ return ((BinaryExpression)finalValue).Right;
}
var targetMemberAccess = MapperData.GetTargetMemberAccess();
- if (ExpressionEvaluation.AreEqual(fallbackValue, targetMemberAccess))
+ if (ExpressionEvaluation.AreEqual(finalValue, targetMemberAccess))
{
return null;
}
- return fallbackValue;
+ return finalValue;
}
#region IEnumerable Members
diff --git a/AgileMapper/DataSources/DefaultValueDataSource.cs b/AgileMapper/DataSources/DefaultValueDataSource.cs
deleted file mode 100644
index 38d1f8191..000000000
--- a/AgileMapper/DataSources/DefaultValueDataSource.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace AgileObjects.AgileMapper.DataSources
-{
- using Members;
-
- internal class DefaultValueDataSource : DataSourceBase
- {
- public DefaultValueDataSource(IMemberMapperData mapperData)
- : base(mapperData.SourceMember, mapperData.GetTargetMemberDefault())
- {
- }
- }
-}
\ No newline at end of file
diff --git a/AgileMapper/DataSources/DefaultValueDataSourceFactory.cs b/AgileMapper/DataSources/DefaultValueDataSourceFactory.cs
deleted file mode 100644
index de2890765..000000000
--- a/AgileMapper/DataSources/DefaultValueDataSourceFactory.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace AgileObjects.AgileMapper.DataSources
-{
- using Members;
-
- internal struct DefaultValueDataSourceFactory : IDataSourceFactory
- {
- public IDataSource Create(IMemberMapperData mapperData)
- => new DefaultValueDataSource(mapperData);
- }
-}
\ No newline at end of file
diff --git a/AgileMapper/DataSources/DefaultValueFallbackDataSourceFactory.cs b/AgileMapper/DataSources/DefaultValueFallbackDataSourceFactory.cs
new file mode 100644
index 000000000..84a7d58cc
--- /dev/null
+++ b/AgileMapper/DataSources/DefaultValueFallbackDataSourceFactory.cs
@@ -0,0 +1,20 @@
+namespace AgileObjects.AgileMapper.DataSources
+{
+ using Members;
+
+ internal struct DefaultValueFallbackDataSourceFactory : IFallbackDataSourceFactory
+ {
+ public IDataSource Create(IMemberMapperData mapperData)
+ => new DefaultValueFallbackDataSource(mapperData);
+
+ private class DefaultValueFallbackDataSource : DataSourceBase
+ {
+ public DefaultValueFallbackDataSource(IMemberMapperData mapperData)
+ : base(mapperData.SourceMember, mapperData.GetTargetMemberDefault())
+ {
+ }
+
+ public override bool IsFallback => true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AgileMapper/DataSources/DictionaryEntryDataSource.cs b/AgileMapper/DataSources/DictionaryEntryDataSource.cs
index d6b6d76b0..9783ea227 100644
--- a/AgileMapper/DataSources/DictionaryEntryDataSource.cs
+++ b/AgileMapper/DataSources/DictionaryEntryDataSource.cs
@@ -1,11 +1,11 @@
namespace AgileObjects.AgileMapper.DataSources
{
- using Extensions.Internal;
#if NET35
using Microsoft.Scripting.Ast;
#else
using System.Linq.Expressions;
#endif
+ using Extensions.Internal;
internal class DictionaryEntryDataSource : DataSourceBase
{
diff --git a/AgileMapper/DataSources/EnumerableMappingDataSource.cs b/AgileMapper/DataSources/EnumerableMappingDataSource.cs
index 059f1d13a..939a6b48f 100644
--- a/AgileMapper/DataSources/EnumerableMappingDataSource.cs
+++ b/AgileMapper/DataSources/EnumerableMappingDataSource.cs
@@ -2,16 +2,16 @@
{
using System;
using System.Linq;
- using Extensions;
- using Extensions.Internal;
- using Members;
- using ObjectPopulation;
- using ObjectPopulation.Enumerables;
#if NET35
using Microsoft.Scripting.Ast;
#else
using System.Linq.Expressions;
#endif
+ using Extensions;
+ using Extensions.Internal;
+ using Members;
+ using ObjectPopulation;
+ using ObjectPopulation.Enumerables;
internal class EnumerableMappingDataSource : DataSourceBase
{
diff --git a/AgileMapper/DataSources/ExistingMemberValueOrDefaultDataSource.cs b/AgileMapper/DataSources/ExistingMemberValueOrDefaultDataSource.cs
deleted file mode 100644
index 4525eb024..000000000
--- a/AgileMapper/DataSources/ExistingMemberValueOrDefaultDataSource.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-namespace AgileObjects.AgileMapper.DataSources
-{
- using Members;
- using Members.Dictionaries;
-#if NET35
- using Microsoft.Scripting.Ast;
-#else
- using System.Linq.Expressions;
-#endif
-
- internal class ExistingMemberValueOrDefaultDataSource : DataSourceBase
- {
- public ExistingMemberValueOrDefaultDataSource(IMemberMapperData mapperData)
- : base(mapperData.SourceMember, GetValue(mapperData), mapperData)
- {
- }
-
- private static Expression GetValue(IMemberMapperData mapperData)
- {
- if (mapperData.TargetMember.IsEnumerable)
- {
- return FallbackToCollection(mapperData)
- ? mapperData.GetFallbackCollectionValue()
- : mapperData.GetTargetMemberDefault();
- }
-
- if (mapperData.TargetMember.IsReadable && !mapperData.UseMemberInitialisations())
- {
- return mapperData.GetTargetMemberAccess();
- }
-
- return mapperData.GetTargetMemberDefault();
- }
-
- private static bool FallbackToCollection(IBasicMapperData mapperData)
- {
- if (mapperData.TargetMember.IsDictionary)
- {
- return true;
- }
-
- if (!(mapperData.TargetMember is DictionaryTargetMember dictionaryTargetMember))
- {
- return true;
- }
-
- return dictionaryTargetMember.HasEnumerableEntries;
- }
- }
-}
\ No newline at end of file
diff --git a/AgileMapper/DataSources/ExistingOrDefaultValueDataSourceFactory.cs b/AgileMapper/DataSources/ExistingOrDefaultValueDataSourceFactory.cs
deleted file mode 100644
index c1335c979..000000000
--- a/AgileMapper/DataSources/ExistingOrDefaultValueDataSourceFactory.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace AgileObjects.AgileMapper.DataSources
-{
- using Members;
-
- internal struct ExistingOrDefaultValueDataSourceFactory : IDataSourceFactory
- {
- public IDataSource Create(IMemberMapperData mapperData)
- => new ExistingMemberValueOrDefaultDataSource(mapperData);
- }
-}
\ No newline at end of file
diff --git a/AgileMapper/DataSources/ExistingOrDefaultValueFallbackDataSourceFactory.cs b/AgileMapper/DataSources/ExistingOrDefaultValueFallbackDataSourceFactory.cs
new file mode 100644
index 000000000..f136fd257
--- /dev/null
+++ b/AgileMapper/DataSources/ExistingOrDefaultValueFallbackDataSourceFactory.cs
@@ -0,0 +1,60 @@
+namespace AgileObjects.AgileMapper.DataSources
+{
+#if NET35
+ using Microsoft.Scripting.Ast;
+#else
+ using System.Linq.Expressions;
+#endif
+ using Members;
+ using Members.Dictionaries;
+
+ internal struct ExistingOrDefaultValueFallbackDataSourceFactory : IFallbackDataSourceFactory
+ {
+ public IDataSource Create(IMemberMapperData mapperData)
+ => new ExistingValueOrDefaultFallbackDataSource(mapperData);
+
+ private class ExistingValueOrDefaultFallbackDataSource : DataSourceBase
+ {
+ public ExistingValueOrDefaultFallbackDataSource(IMemberMapperData mapperData)
+ : base(mapperData.SourceMember, GetValue(mapperData), mapperData)
+ {
+ }
+
+ private static Expression GetValue(IMemberMapperData mapperData)
+ {
+ if (mapperData.TargetMember.IsEnumerable)
+ {
+ return FallbackToCollection(mapperData)
+ ? mapperData.GetFallbackCollectionValue()
+ : mapperData.GetTargetMemberDefault();
+ }
+
+ if (mapperData.TargetMember.IsReadable && !mapperData.UseMemberInitialisations())
+ {
+ return mapperData.TargetMember.IsSimple
+ ? Constants.EmptyExpression
+ : mapperData.GetTargetMemberAccess();
+ }
+
+ return mapperData.GetTargetMemberDefault();
+ }
+
+ private static bool FallbackToCollection(IBasicMapperData mapperData)
+ {
+ if (mapperData.TargetMember.IsDictionary)
+ {
+ return true;
+ }
+
+ if (!(mapperData.TargetMember is DictionaryTargetMember dictionaryTargetMember))
+ {
+ return true;
+ }
+
+ return dictionaryTargetMember.HasEnumerableEntries;
+ }
+
+ public override bool IsFallback => true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AgileMapper/DataSources/Finders/DataSourceFindContext.cs b/AgileMapper/DataSources/Finders/DataSourceFindContext.cs
index 5103d28cd..96f485294 100644
--- a/AgileMapper/DataSources/Finders/DataSourceFindContext.cs
+++ b/AgileMapper/DataSources/Finders/DataSourceFindContext.cs
@@ -26,7 +26,7 @@ public DataSourceFindContext(IChildMemberMappingData childMappingData)
GetConfiguredDataSources(originalChildMapperData));
}
- private IList GetConfiguredDataSources(IMemberMapperData mapperData)
+ private IList GetConfiguredDataSources(IMemberMapperData mapperData)
=> MapperContext.UserConfigurations.GetDataSources(mapperData);
public IChildMemberMappingData ChildMappingData { get; }
@@ -46,7 +46,7 @@ public IDataSource GetFallbackDataSource()
public IDataSource GetFinalDataSource(IDataSource foundDataSource)
=> GetFinalDataSource(foundDataSource, ChildMappingData);
-
+
public IDataSource GetFinalDataSource(IDataSource foundDataSource, IChildMemberMappingData mappingData)
{
var childTargetMember = mappingData.MapperData.TargetMember;
diff --git a/AgileMapper/DataSources/Finders/DataSourceFinder.cs b/AgileMapper/DataSources/Finders/DataSourceFinder.cs
index cf2cab9ca..e0b08824d 100644
--- a/AgileMapper/DataSources/Finders/DataSourceFinder.cs
+++ b/AgileMapper/DataSources/Finders/DataSourceFinder.cs
@@ -6,6 +6,14 @@
internal struct DataSourceFinder
{
+ private static readonly IDataSourceFinder[] _finders =
+ {
+ default(ConfiguredDataSourceFinder),
+ default(MaptimeDataSourceFinder),
+ default(SourceMemberDataSourceFinder),
+ default(MetaMemberDataSourceFinder)
+ };
+
public static DataSourceSet FindFor(IChildMemberMappingData childMappingData)
{
var findContext = new DataSourceFindContext(childMappingData);
@@ -16,7 +24,7 @@ public static DataSourceSet FindFor(IChildMemberMappingData childMappingData)
private static IEnumerable EnumerateDataSources(DataSourceFindContext context)
{
- foreach (var finder in EnumerateFinders())
+ foreach (var finder in _finders)
{
foreach (var dataSource in finder.FindFor(context))
{
@@ -39,13 +47,5 @@ private static IEnumerable EnumerateDataSources(DataSourceFindConte
}
}
}
-
- private static IEnumerable EnumerateFinders()
- {
- yield return default(ConfiguredDataSourceFinder);
- yield return default(MaptimeDataSourceFinder);
- yield return default(SourceMemberDataSourceFinder);
- yield return default(MetaMemberDataSourceFinder);
- }
}
}
\ No newline at end of file
diff --git a/AgileMapper/DataSources/Finders/MetaMemberDataSourceFinder.cs b/AgileMapper/DataSources/Finders/MetaMemberDataSourceFinder.cs
index 8d0421445..6974810d2 100644
--- a/AgileMapper/DataSources/Finders/MetaMemberDataSourceFinder.cs
+++ b/AgileMapper/DataSources/Finders/MetaMemberDataSourceFinder.cs
@@ -371,16 +371,7 @@ private static Expression GetHasEnumerableCheck(Expression enumerableAccess)
return helper.IsEnumerableOrQueryable
? GetLinqMethodCall(nameof(Enumerable.Any), enumerableAccess, helper)
- : GetEnumerableCountCheck(enumerableAccess, helper);
- }
-
- public static Expression GetEnumerableCountCheck(Expression enumerableAccess, EnumerableTypeHelper helper)
- {
- var enumerableCount = helper.GetCountFor(enumerableAccess);
- var zero = ToNumericConverter.Zero.GetConversionTo(enumerableCount.Type);
- var countGreaterThanZero = Expression.GreaterThan(enumerableCount, zero);
-
- return countGreaterThanZero;
+ : helper.GetNonZeroCountCheck(enumerableAccess);
}
}
@@ -447,7 +438,7 @@ public override Expression GetAccess(Expression parentInstance)
private Expression GetCondition(Expression enumerableAccess, EnumerableTypeHelper helper)
{
- var enumerableCheck = HasMetaMemberPart.GetEnumerableCountCheck(enumerableAccess, helper);
+ var enumerableCheck = helper.GetNonZeroCountCheck(enumerableAccess);
if (MapperData.RuleSet.Settings.GuardAccessTo(enumerableAccess))
{
diff --git a/AgileMapper/DataSources/Finders/SourceMemberDataSourceFinder.cs b/AgileMapper/DataSources/Finders/SourceMemberDataSourceFinder.cs
index 0ec0b02da..988260d43 100644
--- a/AgileMapper/DataSources/Finders/SourceMemberDataSourceFinder.cs
+++ b/AgileMapper/DataSources/Finders/SourceMemberDataSourceFinder.cs
@@ -32,7 +32,8 @@ public IEnumerable FindFor(DataSourceFindContext context)
yield return context.GetFallbackDataSource();
}
- if (matchingSourceMemberDataSource.SourceMember == null)
+ if (hasUseableSourceMember ||
+ (matchingSourceMemberDataSource.SourceMember == null))
{
yield break;
}
diff --git a/AgileMapper/DataSources/IDataSource.cs b/AgileMapper/DataSources/IDataSource.cs
index 218c1249b..98c72d870 100644
--- a/AgileMapper/DataSources/IDataSource.cs
+++ b/AgileMapper/DataSources/IDataSource.cs
@@ -19,6 +19,8 @@ internal interface IDataSource : IConditionallyChainable
bool IsConditional { get; }
+ bool IsFallback { get; }
+
ICollection Variables { get; }
Expression AddPreCondition(Expression population);
diff --git a/AgileMapper/DataSources/IDataSourceFactory.cs b/AgileMapper/DataSources/IFallbackDataSourceFactory.cs
similarity index 73%
rename from AgileMapper/DataSources/IDataSourceFactory.cs
rename to AgileMapper/DataSources/IFallbackDataSourceFactory.cs
index 7701f870b..d3d4c2ddf 100644
--- a/AgileMapper/DataSources/IDataSourceFactory.cs
+++ b/AgileMapper/DataSources/IFallbackDataSourceFactory.cs
@@ -2,7 +2,7 @@ namespace AgileObjects.AgileMapper.DataSources
{
using Members;
- internal interface IDataSourceFactory
+ internal interface IFallbackDataSourceFactory
{
IDataSource Create(IMemberMapperData mapperData);
}
diff --git a/AgileMapper/Extensions/Internal/EnumerableExtensions.cs b/AgileMapper/Extensions/Internal/EnumerableExtensions.cs
index cb57c3633..0d5d4fa60 100644
--- a/AgileMapper/Extensions/Internal/EnumerableExtensions.cs
+++ b/AgileMapper/Extensions/Internal/EnumerableExtensions.cs
@@ -39,7 +39,6 @@ public static void AddRange(this List items, IEnu
}
}
#endif
-
[DebuggerStepThrough]
public static T First(this IList items) => items[0];
@@ -221,12 +220,12 @@ private static Expression Chain(
itemValueFactory.Invoke);
}
- public static void CopyTo(this IList sourceList, List targetList, int startIndex = 0)
+ public static void CopyTo(this IList sourceList, List targetList)
=> targetList.AddRange(sourceList);
public static void CopyFrom(this IList targetList, IList sourceList, int startIndex = 0)
{
- for (var i = 0; i < sourceList.Count; i++)
+ for (var i = 0; i < sourceList.Count && i < targetList.Count; i++)
{
targetList[i + startIndex] = sourceList[i];
}
@@ -270,16 +269,16 @@ public static T[] Append(this IList array, T extraItem)
}
}
- public static T[] Append(this IList array, IList extraItems)
+ public static IList Append(this IList array, IList extraItems)
{
if (extraItems.Count == 0)
{
- return array.CopyToArray();
+ return array;
}
if (array.Count == 0)
{
- return extraItems.CopyToArray();
+ return extraItems;
}
if (extraItems.Count == 1)
diff --git a/AgileMapper/Extensions/Internal/StringExpressionExtensions.cs b/AgileMapper/Extensions/Internal/StringExpressionExtensions.cs
index d1d22f324..09e9b767a 100644
--- a/AgileMapper/Extensions/Internal/StringExpressionExtensions.cs
+++ b/AgileMapper/Extensions/Internal/StringExpressionExtensions.cs
@@ -13,7 +13,7 @@
internal static class StringExpressionExtensions
{
- public static readonly Expression EmptyString = Expression.Field(null, typeof(string), "Empty");
+ public static readonly Expression EmptyString = Expression.Field(null, typeof(string), nameof(string.Empty));
public static readonly Expression Underscore = "_".ToConstantExpression();
private static readonly MethodInfo _stringJoinMethod;
@@ -23,7 +23,7 @@ static StringExpressionExtensions()
{
var stringMethods = typeof(string)
.GetPublicStaticMethods()
- .Filter(m => m.Name == "Join" || m.Name == "Concat")
+ .Filter(m => m.Name == nameof(string.Join) || m.Name == nameof(string.Concat))
.Project(m => new
{
Method = m,
@@ -33,18 +33,30 @@ static StringExpressionExtensions()
.ToArray();
_stringJoinMethod = stringMethods.First(m =>
- (m.Method.Name == "Join") &&
+ (m.Method.Name == nameof(string.Join)) &&
(m.Parameters.Length == 2) &&
(m.Parameters[0].ParameterType == typeof(string)) &&
(m.Parameters[1].ParameterType == typeof(string[]))).Method;
_stringConcatMethods = stringMethods
- .Filter(m => (m.Method.Name == "Concat") && (m.FirstParameterType == typeof(string)))
+ .Filter(m => (m.Method.Name == nameof(string.Concat)) && (m.FirstParameterType == typeof(string)))
.OrderBy(m => m.Parameters.Length)
.Project(m => m.Method)
.ToArray();
}
+ public static Expression GetIsNullOrWhiteSpaceCall(Expression stringValue)
+ {
+ return Expression.Call(
+#if NET35
+ typeof(StringExtensions)
+#else
+ typeof(string)
+#endif
+ .GetPublicStaticMethod("IsNullOrWhiteSpace"),
+ stringValue);
+ }
+
public static MethodInfo GetConcatMethod(int parameterCount)
=> _stringConcatMethods.First(m => m.GetParameters().Length == parameterCount);
@@ -52,7 +64,7 @@ public static Expression GetStringConcatCall(this IList expressions)
{
if (expressions.None())
{
- return string.Empty.ToConstantExpression();
+ return EmptyString;
}
if (expressions.HasOne())
diff --git a/AgileMapper/MappingRuleSet.cs b/AgileMapper/MappingRuleSet.cs
index a84ac6611..9d015972e 100644
--- a/AgileMapper/MappingRuleSet.cs
+++ b/AgileMapper/MappingRuleSet.cs
@@ -21,19 +21,24 @@ public MappingRuleSet(
MappingRuleSetSettings settings,
IEnumerablePopulationStrategy enumerablePopulationStrategy,
IRepeatMappingStrategy repeatMappingStrategy,
- IMemberPopulationFactory populationFactory,
- IDataSourceFactory fallbackDataSourceFactory,
+ IPopulationGuardFactory populationGuardFactory,
+ IFallbackDataSourceFactory fallbackDataSourceFactory,
IRootMapperKeyFactory rootMapperKeyFactory)
+ : this(name)
{
- Name = name;
Settings = settings;
EnumerablePopulationStrategy = enumerablePopulationStrategy;
RepeatMappingStrategy = repeatMappingStrategy;
- PopulationFactory = populationFactory;
+ PopulationGuardFactory = populationGuardFactory;
FallbackDataSourceFactory = fallbackDataSourceFactory;
RootMapperKeyFactory = rootMapperKeyFactory;
}
+ public MappingRuleSet(string name)
+ {
+ Name = name;
+ }
+
public string Name { get; }
public Expression NameConstant => _nameConstant ?? (_nameConstant = Name.ToConstantExpression());
@@ -44,9 +49,9 @@ public MappingRuleSet(
public IRepeatMappingStrategy RepeatMappingStrategy { get; }
- public IMemberPopulationFactory PopulationFactory { get; }
+ public IPopulationGuardFactory PopulationGuardFactory { get; }
- public IDataSourceFactory FallbackDataSourceFactory { get; }
+ public IFallbackDataSourceFactory FallbackDataSourceFactory { get; }
public IRootMapperKeyFactory RootMapperKeyFactory { get; }
}
diff --git a/AgileMapper/MappingRuleSetCollection.cs b/AgileMapper/MappingRuleSetCollection.cs
index ab377af88..8b9b91372 100644
--- a/AgileMapper/MappingRuleSetCollection.cs
+++ b/AgileMapper/MappingRuleSetCollection.cs
@@ -19,8 +19,8 @@ internal class MappingRuleSetCollection
MappingRuleSetSettings.ForInMemoryMapping(allowCloneEntityKeyMapping: true),
default(CopySourceEnumerablePopulationStrategy),
default(MapRepeatedCallRepeatMappingStrategy),
- DefaultMemberPopulationFactory.Instance,
- default(ExistingOrDefaultValueDataSourceFactory),
+ default(NullMemberPopulationGuardFactory),
+ default(ExistingOrDefaultValueFallbackDataSourceFactory),
default(RootMapperKeyFactory));
private static readonly MappingRuleSet _overwrite = new MappingRuleSet(
@@ -28,8 +28,8 @@ internal class MappingRuleSetCollection
MappingRuleSetSettings.ForInMemoryMapping(rootHasPopulatedTarget: true),
default(OverwriteEnumerablePopulationStrategy),
default(MapRepeatedCallRepeatMappingStrategy),
- DefaultMemberPopulationFactory.Instance,
- default(DefaultValueDataSourceFactory),
+ default(NullMemberPopulationGuardFactory),
+ default(DefaultValueFallbackDataSourceFactory),
default(RootMapperKeyFactory));
private static readonly MappingRuleSet _project = new MappingRuleSet(
@@ -40,23 +40,24 @@ internal class MappingRuleSetCollection
UseSingleRootMappingExpression = true,
AllowEntityKeyMapping = true,
AllowCloneEntityKeyMapping = true,
+ AllowGuardedBindings = true,
GuardAccessTo = value => value.Type.IsComplex(),
ExpressionIsSupported = value => value.CanBeProjected(),
AllowEnumerableAssignment = true
},
default(ProjectSourceEnumerablePopulationStrategy),
default(MapToDepthRepeatMappingStrategy),
- DefaultMemberPopulationFactory.Instance,
- default(DefaultValueDataSourceFactory),
+ default(NullMemberPopulationGuardFactory),
+ default(DefaultValueFallbackDataSourceFactory),
default(QueryProjectorMapperKeyFactory));
private static readonly MappingRuleSet _merge = new MappingRuleSet(
Constants.Merge,
- MappingRuleSetSettings.ForInMemoryMapping(rootHasPopulatedTarget: true),
+ MappingRuleSetSettings.ForInMemoryMapping(rootHasPopulatedTarget: true, allowGuardedBindings: false),
default(MergeEnumerablePopulationStrategy),
default(MapRepeatedCallRepeatMappingStrategy),
- new MemberMergePopulationFactory(),
- default(ExistingOrDefaultValueDataSourceFactory),
+ default(MemberMergePopulationGuardFactory),
+ default(ExistingOrDefaultValueFallbackDataSourceFactory),
default(RootMapperKeyFactory));
public static readonly MappingRuleSetCollection Default =
diff --git a/AgileMapper/MappingRuleSetSettings.cs b/AgileMapper/MappingRuleSetSettings.cs
index b3acd85b3..45d62c50a 100644
--- a/AgileMapper/MappingRuleSetSettings.cs
+++ b/AgileMapper/MappingRuleSetSettings.cs
@@ -11,6 +11,7 @@ internal class MappingRuleSetSettings
{
public static MappingRuleSetSettings ForInMemoryMapping(
bool rootHasPopulatedTarget = false,
+ bool allowGuardedBindings = true,
bool allowCloneEntityKeyMapping = false)
{
return new MappingRuleSetSettings
@@ -20,6 +21,7 @@ public static MappingRuleSetSettings ForInMemoryMapping(
SourceElementsCouldBeNull = true,
UseTryCatch = true,
CheckDerivedSourceTypes = true,
+ AllowGuardedBindings = allowGuardedBindings,
AllowCloneEntityKeyMapping = allowCloneEntityKeyMapping,
GuardAccessTo = value => true,
ExpressionIsSupported = value => true,
@@ -44,6 +46,8 @@ public static MappingRuleSetSettings ForInMemoryMapping(
public bool CheckDerivedSourceTypes { get; set; }
+ public bool AllowGuardedBindings { get; set; }
+
public bool AllowEntityKeyMapping { get; set; }
public bool AllowCloneEntityKeyMapping { get; set; }
diff --git a/AgileMapper/Members/ExpressionInfoFinder.cs b/AgileMapper/Members/ExpressionInfoFinder.cs
index 796a96b0b..85387e83a 100644
--- a/AgileMapper/Members/ExpressionInfoFinder.cs
+++ b/AgileMapper/Members/ExpressionInfoFinder.cs
@@ -3,10 +3,6 @@ namespace AgileObjects.AgileMapper.Members
using System;
using System.Collections.Generic;
using System.Linq;
- using Extensions;
- using Extensions.Internal;
- using NetStandardPolyfills;
- using ReadableExpressions.Extensions;
#if NET35
using Microsoft.Scripting.Ast;
using static Microsoft.Scripting.Ast.ExpressionType;
@@ -14,6 +10,10 @@ namespace AgileObjects.AgileMapper.Members
using System.Linq.Expressions;
using static System.Linq.Expressions.ExpressionType;
#endif
+ using Extensions;
+ using Extensions.Internal;
+ using NetStandardPolyfills;
+ using ReadableExpressions.Extensions;
using static Member;
internal class ExpressionInfoFinder
diff --git a/AgileMapper/Members/Population/DefaultMemberPopulationFactory.cs b/AgileMapper/Members/Population/DefaultMemberPopulationFactory.cs
deleted file mode 100644
index c1c8206e5..000000000
--- a/AgileMapper/Members/Population/DefaultMemberPopulationFactory.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-namespace AgileObjects.AgileMapper.Members.Population
-{
- using Extensions.Internal;
-#if NET35
- using Microsoft.Scripting.Ast;
-#else
- using System.Linq.Expressions;
-#endif
-
- internal class DefaultMemberPopulationFactory : MemberPopulationFactoryBase
- {
- public static readonly IMemberPopulationFactory Instance = new DefaultMemberPopulationFactory();
-
- protected override Expression GetPopulationGuard(IMemberPopulationContext context)
- => context.PopulateCondition;
-
- protected override Expression GetGuardedBindingValue(Expression bindingValue, Expression populationGuard)
- {
- if (populationGuard == null)
- {
- return bindingValue;
- }
-
- return Expression.Condition(
- populationGuard,
- bindingValue,
- bindingValue.Type.ToDefaultExpression());
- }
-
- public override Expression GetGuardedPopulation(
- Expression population,
- Expression populationGuard,
- bool useSingleExpression)
- {
- return useSingleExpression
- ? population
- : base.GetGuardedPopulation(population, populationGuard, false);
- }
- }
-}
\ No newline at end of file
diff --git a/AgileMapper/Members/Population/IMemberPopulationContext.cs b/AgileMapper/Members/Population/IMemberPopulationContext.cs
index 277554294..de9ff6443 100644
--- a/AgileMapper/Members/Population/IMemberPopulationContext.cs
+++ b/AgileMapper/Members/Population/IMemberPopulationContext.cs
@@ -5,16 +5,11 @@ namespace AgileObjects.AgileMapper.Members.Population
#else
using System.Linq.Expressions;
#endif
- using DataSources;
internal interface IMemberPopulationContext
{
IMemberMapperData MapperData { get; }
- bool IsSuccessful { get; }
-
- DataSourceSet DataSources { get; }
-
Expression PopulateCondition { get; }
}
}
\ No newline at end of file
diff --git a/AgileMapper/Members/Population/IMemberPopulationFactory.cs b/AgileMapper/Members/Population/IPopulationGuardFactory.cs
similarity index 57%
rename from AgileMapper/Members/Population/IMemberPopulationFactory.cs
rename to AgileMapper/Members/Population/IPopulationGuardFactory.cs
index 0d1582192..d76c8ded5 100644
--- a/AgileMapper/Members/Population/IMemberPopulationFactory.cs
+++ b/AgileMapper/Members/Population/IPopulationGuardFactory.cs
@@ -6,8 +6,8 @@ namespace AgileObjects.AgileMapper.Members.Population
using System.Linq.Expressions;
#endif
- internal interface IMemberPopulationFactory
+ internal interface IPopulationGuardFactory
{
- Expression GetPopulation(IMemberPopulationContext context);
+ Expression GetPopulationGuard(IMemberPopulationContext context);
}
}
\ No newline at end of file
diff --git a/AgileMapper/Members/Population/MemberMergePopulationFactory.cs b/AgileMapper/Members/Population/MemberMergePopulationGuardFactory.cs
similarity index 80%
rename from AgileMapper/Members/Population/MemberMergePopulationFactory.cs
rename to AgileMapper/Members/Population/MemberMergePopulationGuardFactory.cs
index f81f14429..b021ee35d 100644
--- a/AgileMapper/Members/Population/MemberMergePopulationFactory.cs
+++ b/AgileMapper/Members/Population/MemberMergePopulationGuardFactory.cs
@@ -6,9 +6,9 @@ namespace AgileObjects.AgileMapper.Members.Population
using System.Linq.Expressions;
#endif
- internal class MemberMergePopulationFactory : MemberPopulationFactoryBase
+ internal struct MemberMergePopulationGuardFactory : IPopulationGuardFactory
{
- protected override Expression GetPopulationGuard(IMemberPopulationContext context)
+ public Expression GetPopulationGuard(IMemberPopulationContext context)
{
var mapperData = context.MapperData;
var populateCondition = context.PopulateCondition;
@@ -51,8 +51,5 @@ private static bool SkipPopulationGuarding(IBasicMapperData mapperData)
return skipObjectValueGuarding;
}
-
- protected override Expression GetGuardedBindingValue(Expression bindingValue, Expression populationGuard)
- => bindingValue;
}
}
\ No newline at end of file
diff --git a/AgileMapper/Members/Population/MemberPopulationFactoryBase.cs b/AgileMapper/Members/Population/MemberPopulationFactoryBase.cs
deleted file mode 100644
index ec8b55d77..000000000
--- a/AgileMapper/Members/Population/MemberPopulationFactoryBase.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-namespace AgileObjects.AgileMapper.Members.Population
-{
- using System.Collections.Generic;
-#if NET35
- using Microsoft.Scripting.Ast;
-#else
- using System.Linq.Expressions;
-#endif
- using Extensions.Internal;
-
- internal abstract class MemberPopulationFactoryBase : IMemberPopulationFactory
- {
- public Expression GetPopulation(IMemberPopulationContext context)
- {
- if (!context.IsSuccessful)
- {
- return context.DataSources.ValueExpression;
- }
-
- var useSingleExpression = context.MapperData.UseMemberInitialisations();
- var populationGuard = GetPopulationGuard(context);
-
- var population = useSingleExpression
- ? GetBinding(context, populationGuard)
- : context.MapperData.TargetMember.IsReadOnly
- ? GetReadOnlyMemberPopulation(context)
- : context.DataSources.GetPopulationExpression();
-
- if (context.DataSources.Variables.Any())
- {
- population = GetPopulationWithVariables(population, context.DataSources.Variables);
- }
-
- return GetGuardedPopulation(population, populationGuard, useSingleExpression);
- }
-
- private static Expression GetPopulationWithVariables(Expression population, IList variables)
- {
- if (population.NodeType != ExpressionType.Block)
- {
- return Expression.Block(variables, population);
- }
-
- var populationBlock = (BlockExpression)population;
-
- if (populationBlock.Variables.Any())
- {
- variables = variables.Append(populationBlock.Variables);
- }
-
- return populationBlock.Update(variables, populationBlock.Expressions);
- }
-
- protected abstract Expression GetPopulationGuard(IMemberPopulationContext context);
-
- private Expression GetBinding(IMemberPopulationContext context, Expression populationGuard)
- {
- var bindingValue = context.DataSources.ValueExpression;
- var guardedBindingValue = GetGuardedBindingValue(bindingValue, populationGuard);
- var binding = context.MapperData.GetTargetMemberPopulation(guardedBindingValue);
-
- return binding;
- }
-
- protected abstract Expression GetGuardedBindingValue(Expression bindingValue, Expression populationGuard);
-
- private static Expression GetReadOnlyMemberPopulation(IMemberPopulationContext context)
- {
- var dataSourcesValue = context.DataSources.ValueExpression;
- var targetMemberAccess = context.MapperData.GetTargetMemberAccess();
- var targetMemberNotNull = targetMemberAccess.GetIsNotDefaultComparison();
-
- return Expression.IfThen(targetMemberNotNull, dataSourcesValue);
- }
-
- public virtual Expression GetGuardedPopulation(
- Expression population,
- Expression populationGuard,
- bool useSingleExpression)
- {
- return (populationGuard != null)
- ? Expression.IfThen(populationGuard, population)
- : population;
- }
- }
-}
\ No newline at end of file
diff --git a/AgileMapper/Members/Population/MemberPopulator.cs b/AgileMapper/Members/Population/MemberPopulator.cs
index 91cd82338..3776cee57 100644
--- a/AgileMapper/Members/Population/MemberPopulator.cs
+++ b/AgileMapper/Members/Population/MemberPopulator.cs
@@ -2,44 +2,39 @@ namespace AgileObjects.AgileMapper.Members.Population
{
using System;
using System.Linq;
- using Configuration;
- using DataSources;
- using ReadableExpressions;
#if NET35
using Microsoft.Scripting.Ast;
#else
using System.Linq.Expressions;
#endif
+ using Configuration;
+ using DataSources;
+ using Extensions.Internal;
+ using ReadableExpressions;
internal class MemberPopulator : IMemberPopulationContext, IMemberPopulator
{
+ private readonly DataSourceSet _dataSources;
+
private MemberPopulator(DataSourceSet dataSources, Expression populateCondition = null)
{
- DataSources = dataSources;
+ _dataSources = dataSources;
PopulateCondition = populateCondition;
}
#region Factory Methods
- public static IMemberPopulator WithRegistration(
- IChildMemberMappingData mappingData,
- DataSourceSet dataSources,
- Expression populateCondition)
+ public static IMemberPopulator WithRegistration(DataSourceSet dataSources, Expression populateCondition)
{
- var memberPopulation = WithoutRegistration(mappingData, dataSources, populateCondition);
+ var memberPopulation = WithoutRegistration(dataSources, populateCondition);
memberPopulation.MapperData.RegisterTargetMemberDataSourcesIfRequired(dataSources);
return memberPopulation;
}
- public static IMemberPopulator WithoutRegistration(
- IChildMemberMappingData mappingData,
- DataSourceSet dataSources,
- Expression populateCondition = null)
- {
- return new MemberPopulator(dataSources, populateCondition);
- }
+ public static IMemberPopulator WithoutRegistration(DataSourceSet dataSources, Expression populateCondition = null)
+ => new MemberPopulator(dataSources, populateCondition);
public static IMemberPopulator Unmappable(IMemberMapperData mapperData, string reason)
=> CreateNullMemberPopulation(mapperData, targetMember => $"No way to populate {targetMember.Name} ({reason})");
@@ -82,18 +77,126 @@ private static DataSourceSet CreateNullDataSourceSet(
#endregion
- public IMemberMapperData MapperData => DataSources.MapperData;
-
- public bool IsSuccessful => CanPopulate;
+ public IMemberMapperData MapperData => _dataSources.MapperData;
- public bool CanPopulate => DataSources.HasValue;
-
- public DataSourceSet DataSources { get; }
+ public bool CanPopulate => _dataSources.HasValue;
public Expression PopulateCondition { get; }
public Expression GetPopulation()
- => MapperData.RuleSet.PopulationFactory.GetPopulation(this);
+ {
+ if (!CanPopulate)
+ {
+ return _dataSources.ValueExpression;
+ }
+
+ var populationGuard = MapperData
+ .RuleSet
+ .PopulationGuardFactory
+ .GetPopulationGuard(this);
+
+ var useSingleExpression = MapperData.UseMemberInitialisations();
+
+ var population = useSingleExpression
+ ? GetBinding(populationGuard)
+ : MapperData.TargetMember.IsReadOnly
+ ? GetReadOnlyMemberPopulation()
+ : GetPopulationExpression();
+
+ if (_dataSources.Variables.Any())
+ {
+ population = GetPopulationWithVariables(population);
+ }
+
+ if (useSingleExpression && MapperData.RuleSet.Settings.AllowGuardedBindings)
+ {
+ return population;
+ }
+
+ return (populationGuard != null)
+ ? Expression.IfThen(populationGuard, population)
+ : population;
+ }
+
+ private Expression GetBinding(Expression populationGuard)
+ {
+ var bindingValue = _dataSources.ValueExpression;
+
+ if (MapperData.RuleSet.Settings.AllowGuardedBindings && (populationGuard != null))
+ {
+ bindingValue = Expression.Condition(
+ populationGuard,
+ bindingValue,
+ bindingValue.Type.ToDefaultExpression());
+ }
+
+ return MapperData.GetTargetMemberPopulation(bindingValue);
+ }
+
+ private Expression GetReadOnlyMemberPopulation()
+ {
+ var targetMemberAccess = MapperData.GetTargetMemberAccess();
+ var targetMemberNotNull = targetMemberAccess.GetIsNotDefaultComparison();
+
+ return Expression.IfThen(targetMemberNotNull, _dataSources.ValueExpression);
+ }
+
+ private Expression GetPopulationExpression()
+ {
+ var finalValue = _dataSources.GetFinalValueOrNull();
+ var excludeFinalValue = finalValue == null;
+ var finalDataSourceIndex = _dataSources.Count - 1;
+
+ Expression population = null;
+
+ for (var i = finalDataSourceIndex; i >= 0; --i)
+ {
+ var dataSource = _dataSources[i];
+
+ if (i == finalDataSourceIndex)
+ {
+ if (excludeFinalValue)
+ {
+ continue;
+ }
+
+ population = MapperData.GetTargetMemberPopulation(finalValue);
+
+ if (dataSource.IsConditional)
+ {
+ population = dataSource.AddCondition(population);
+ }
+
+ population = dataSource.AddPreCondition(population);
+ continue;
+ }
+
+ var memberPopulation = MapperData.GetTargetMemberPopulation(dataSource.Value);
+
+ population = dataSource.AddCondition(memberPopulation, population);
+ population = dataSource.AddPreCondition(population);
+ }
+
+ return population;
+ }
+
+ private Expression GetPopulationWithVariables(Expression population)
+ {
+ if (population.NodeType != ExpressionType.Block)
+ {
+ return Expression.Block(_dataSources.Variables, population);
+ }
+
+ var populationBlock = (BlockExpression)population;
+ var variables = _dataSources.Variables;
+
+ if (Enumerable.Any(populationBlock.Variables))
+ {
+ variables = variables.Append(populationBlock.Variables);
+ }
+
+ return Expression.Block(variables, populationBlock.Expressions);
+ }
#region ExcludeFromCodeCoverage
#if DEBUG
@@ -101,6 +204,6 @@ public Expression GetPopulation()
#endif
#endregion
public override string ToString()
- => $"{MapperData.TargetMember} ({DataSources.Count()} data source(s))";
+ => $"{MapperData.TargetMember} ({_dataSources.Count()} data source(s))";
}
}
\ No newline at end of file
diff --git a/AgileMapper/Members/Population/MemberPopulatorFactory.cs b/AgileMapper/Members/Population/MemberPopulatorFactory.cs
index 731696cd4..74e2ef23b 100644
--- a/AgileMapper/Members/Population/MemberPopulatorFactory.cs
+++ b/AgileMapper/Members/Population/MemberPopulatorFactory.cs
@@ -20,7 +20,7 @@ internal class MemberPopulatorFactory
GlobalContext.Instance
.MemberCache
.GetTargetMembers(mapperData.TargetType)
- .ProjectToArray(tm => mapperData.TargetMember.Append(tm)));
+ .ProjectToArray(mapperData.TargetMember.Append));
private readonly Func> _targetMembersFactory;
@@ -35,12 +35,12 @@ public IEnumerable Create(IObjectMappingData mappingData)
.Invoke(mappingData.MapperData)
.Project(tm =>
{
- var memberPopulation = Create(tm, mappingData);
+ var memberPopulator = Create(tm, mappingData);
- if (memberPopulation.CanPopulate ||
+ if (memberPopulator.CanPopulate ||
mappingData.MappingContext.AddUnsuccessfulMemberPopulations)
{
- return memberPopulation;
+ return memberPopulator;
}
return null;
@@ -73,7 +73,7 @@ private static IMemberPopulator Create(QualifiedMember targetMember, IObjectMapp
return MemberPopulator.NoDataSource(childMapperData);
}
- return MemberPopulator.WithRegistration(childMappingData, dataSources, populateCondition);
+ return MemberPopulator.WithRegistration(dataSources, populateCondition);
}
private static bool TargetMemberIsUnmappable(
diff --git a/AgileMapper/Members/Population/NullMemberPopulationGuardFactory.cs b/AgileMapper/Members/Population/NullMemberPopulationGuardFactory.cs
new file mode 100644
index 000000000..9baa3ea45
--- /dev/null
+++ b/AgileMapper/Members/Population/NullMemberPopulationGuardFactory.cs
@@ -0,0 +1,14 @@
+namespace AgileObjects.AgileMapper.Members.Population
+{
+#if NET35
+ using Microsoft.Scripting.Ast;
+#else
+ using System.Linq.Expressions;
+#endif
+
+ internal partial struct NullMemberPopulationGuardFactory : IPopulationGuardFactory
+ {
+ public Expression GetPopulationGuard(IMemberPopulationContext context)
+ => context.PopulateCondition;
+ }
+}
\ No newline at end of file
diff --git a/AgileMapper/ObjectPopulation/ComplexTypes/ComplexTypeMappingExpressionFactory.cs b/AgileMapper/ObjectPopulation/ComplexTypes/ComplexTypeMappingExpressionFactory.cs
index a11e5a2cf..a6cd8fbc2 100644
--- a/AgileMapper/ObjectPopulation/ComplexTypes/ComplexTypeMappingExpressionFactory.cs
+++ b/AgileMapper/ObjectPopulation/ComplexTypes/ComplexTypeMappingExpressionFactory.cs
@@ -48,7 +48,7 @@ protected override bool TargetCannotBeMapped(IObjectMappingData mappingData, out
var targetType = mappingData.MapperData.TargetType;
- if (targetType.IsAbstract() && DerivedTypesExistForTarget(mappingData))
+ if (targetType.IsAbstract() && DerivedTypesExistForTarget(mappingData.MapperData))
{
return base.TargetCannotBeMapped(mappingData, out reason);
}
@@ -57,17 +57,16 @@ protected override bool TargetCannotBeMapped(IObjectMappingData mappingData, out
return true;
}
- private static bool DerivedTypesExistForTarget(IObjectMappingData mappingData)
+ private static bool DerivedTypesExistForTarget(IMemberMapperData mapperData)
{
- var configuredImplementationTypePairs = mappingData
- .MapperData
+ var configuredImplementationTypePairs = mapperData
.MapperContext
.UserConfigurations
.DerivedTypes
- .GetImplementationTypePairsFor(mappingData.MapperData, mappingData.MapperData.MapperContext);
+ .GetImplementationTypePairsFor(mapperData, mapperData.MapperContext);
return configuredImplementationTypePairs.Any() ||
- mappingData.MapperData.GetDerivedTargetTypes().Any();
+ mapperData.GetDerivedTargetTypes().Any();
}
#region Short-Circuits
diff --git a/AgileMapper/ObjectPopulation/ComplexTypes/MultiStatementPopulationExpressionFactory.cs b/AgileMapper/ObjectPopulation/ComplexTypes/MultiStatementPopulationExpressionFactory.cs
index a9e8cdb3e..91830fe5a 100644
--- a/AgileMapper/ObjectPopulation/ComplexTypes/MultiStatementPopulationExpressionFactory.cs
+++ b/AgileMapper/ObjectPopulation/ComplexTypes/MultiStatementPopulationExpressionFactory.cs
@@ -1,13 +1,13 @@
namespace AgileObjects.AgileMapper.ObjectPopulation.ComplexTypes
{
using System.Collections.Generic;
- using Members;
- using Members.Population;
#if NET35
using Microsoft.Scripting.Ast;
#else
using System.Linq.Expressions;
#endif
+ using Members;
+ using Members.Population;
using static CallbackPosition;
internal class MultiStatementPopulationExpressionFactory : PopulationExpressionFactoryBase
diff --git a/AgileMapper/ObjectPopulation/ComplexTypes/PopulationExpressionFactoryBase.cs b/AgileMapper/ObjectPopulation/ComplexTypes/PopulationExpressionFactoryBase.cs
index 133cfa07c..60d57499e 100644
--- a/AgileMapper/ObjectPopulation/ComplexTypes/PopulationExpressionFactoryBase.cs
+++ b/AgileMapper/ObjectPopulation/ComplexTypes/PopulationExpressionFactoryBase.cs
@@ -18,7 +18,7 @@ internal abstract class PopulationExpressionFactoryBase
public IEnumerable GetPopulation(MappingCreationContext context)
{
var mappingData = context.MappingData;
- var mapperData = context.MapperData;
+ var mapperData = mappingData.MapperData;
GetCreationCallbacks(context, out var preCreationCallback, out var postCreationCallback);
@@ -26,16 +26,26 @@ public IEnumerable GetPopulation(MappingCreationContext context)
if (context.InstantiateLocalVariable && mapperData.Context.UseLocalVariable)
{
- yield return preCreationCallback;
-
- var assignCreatedObject = postCreationCallback != null;
+ if (preCreationCallback != null)
+ {
+ yield return preCreationCallback;
+ }
+
+ var hasPostCreationCallback = postCreationCallback != null;
+ var assignCreatedObject = hasPostCreationCallback;
yield return GetLocalVariableInstantiation(assignCreatedObject, populationsAndCallbacks, mappingData);
- yield return postCreationCallback;
+ if (hasPostCreationCallback)
+ {
+ yield return postCreationCallback;
+ }
}
- yield return GetObjectRegistrationCallOrNull(mapperData);
+ if (IncludeObjectRegistration(mapperData))
+ {
+ yield return GetObjectRegistrationCall(mapperData);
+ }
foreach (var population in populationsAndCallbacks)
{
@@ -113,15 +123,15 @@ protected virtual Expression GetTargetObjectCreation(
#region Object Registration
- private static Expression GetObjectRegistrationCallOrNull(ObjectMapperData mapperData)
+ private static bool IncludeObjectRegistration(ObjectMapperData mapperData)
{
- if (mapperData.TargetTypeWillNotBeMappedAgain ||
- !mapperData.CacheMappedObjects ||
- !mapperData.RuleSet.Settings.AllowObjectTracking)
- {
- return null;
- }
+ return mapperData.CacheMappedObjects &&
+ mapperData.RuleSet.Settings.AllowObjectTracking &&
+ !mapperData.TargetTypeWillNotBeMappedAgain;
+ }
+ private static Expression GetObjectRegistrationCall(ObjectMapperData mapperData)
+ {
var registerMethod = typeof(IObjectMappingDataUntyped)
.GetPublicInstanceMethod(nameof(IObjectMappingDataUntyped.Register))
.MakeGenericMethod(mapperData.SourceType, mapperData.TargetType);
diff --git a/AgileMapper/ObjectPopulation/DerivedComplexTypeMappingsFactory.cs b/AgileMapper/ObjectPopulation/DerivedComplexTypeMappingsFactory.cs
index d3e5663a9..450fc6790 100644
--- a/AgileMapper/ObjectPopulation/DerivedComplexTypeMappingsFactory.cs
+++ b/AgileMapper/ObjectPopulation/DerivedComplexTypeMappingsFactory.cs
@@ -5,14 +5,17 @@ namespace AgileObjects.AgileMapper.ObjectPopulation
using System.Linq;
#if NET35
using Microsoft.Scripting.Ast;
+ using static Microsoft.Scripting.Ast.Expression;
#else
using System.Linq.Expressions;
+ using static System.Linq.Expressions.Expression;
#endif
using Configuration;
using Extensions;
using Extensions.Internal;
using Members;
using NetStandardPolyfills;
+ using static Constants;
internal static class DerivedComplexTypeMappingsFactory
{
@@ -22,57 +25,69 @@ public static Expression CreateFor(IObjectMappingData declaredTypeMappingData)
if (DoNotMapDerivedTypes(declaredTypeMapperData))
{
- return Constants.EmptyExpression;
+ return EmptyExpression;
}
- var derivedSourceTypes = declaredTypeMapperData.RuleSet.Settings.CheckDerivedSourceTypes
- ? declaredTypeMapperData.GetDerivedSourceTypes()
- : Constants.EmptyTypeArray;
+ var derivedSourceTypes = GetDerivedSourceTypesIfNecessary(declaredTypeMapperData);
+ var hasDerivedSourceTypes = derivedSourceTypes.Any();
+ var hasNoDerivedSourceTypes = !hasDerivedSourceTypes;
+
+ var derivedTargetTypes = GetDerivedTargetTypesIfNecessary(declaredTypeMapperData);
+ var hasDerivedTargetTypes = derivedTargetTypes.Any();
- var derivedTargetTypes = GetDerivedTargetTypesIfNecessary(declaredTypeMappingData);
var derivedTypePairs = GetTypePairsFor(declaredTypeMapperData, declaredTypeMapperData);
+ var hasDerivedTypePairs = derivedTypePairs.Any();
- if (derivedSourceTypes.None() && derivedTargetTypes.None() && derivedTypePairs.None())
+ if (hasNoDerivedSourceTypes && !hasDerivedTargetTypes && !hasDerivedTypePairs)
{
- return Constants.EmptyExpression;
+ return EmptyExpression;
}
var derivedTypeMappingExpressions = new List();
- AddDeclaredSourceTypeMappings(
- derivedTypePairs,
- declaredTypeMappingData,
- derivedTypeMappingExpressions,
- out var declaredTypeHasUnconditionalTypePair);
-
- if (declaredTypeHasUnconditionalTypePair && derivedSourceTypes.None())
+ if (hasDerivedTypePairs)
{
- return derivedTypeMappingExpressions.First();
+ AddDeclaredSourceTypeMappings(
+ derivedTypePairs,
+ declaredTypeMappingData,
+ derivedTypeMappingExpressions,
+ out var declaredTypeHasUnconditionalTypePair);
+
+ if (declaredTypeHasUnconditionalTypePair && hasNoDerivedSourceTypes)
+ {
+ return derivedTypeMappingExpressions.First();
+ }
}
var typedObjectVariables = new List();
- AddDerivedSourceTypeMappings(
- derivedSourceTypes,
- declaredTypeMappingData,
- typedObjectVariables,
- derivedTypeMappingExpressions);
+ if (hasDerivedSourceTypes)
+ {
+ AddDerivedSourceTypeMappings(
+ derivedSourceTypes,
+ declaredTypeMappingData,
+ typedObjectVariables,
+ derivedTypeMappingExpressions);
+ }
- AddDerivedTargetTypeMappings(
- declaredTypeMappingData,
- derivedTargetTypes,
- derivedTypeMappingExpressions);
+ if (hasDerivedTargetTypes)
+ {
+ AddDerivedTargetTypeMappings(
+ declaredTypeMappingData,
+ derivedTargetTypes,
+ derivedTypeMappingExpressions);
+ }
if (derivedTypeMappingExpressions.None())
{
- return Constants.EmptyExpression;
+ return EmptyExpression;
}
return typedObjectVariables.Any()
- ? Expression.Block(typedObjectVariables, derivedTypeMappingExpressions)
+ ? Block(typedObjectVariables, derivedTypeMappingExpressions)
: derivedTypeMappingExpressions.HasOne()
? derivedTypeMappingExpressions.First()
- : Expression.Block(derivedTypeMappingExpressions);
+ : Block(derivedTypeMappingExpressions);
}
private static bool DoNotMapDerivedTypes(IMemberMapperData mapperData)
@@ -85,14 +100,18 @@ private static bool DoNotMapDerivedTypes(IMemberMapperData mapperData)
return mapperData.HasSameSourceAsParent();
}
- private static ICollection GetDerivedTargetTypesIfNecessary(IObjectMappingData mappingData)
+ private static ICollection GetDerivedSourceTypesIfNecessary(IMemberMapperData mapperData)
{
- if (mappingData.MapperData.TargetIsDefinitelyUnpopulated())
- {
- return Constants.EmptyTypeArray;
- }
+ return mapperData.RuleSet.Settings.CheckDerivedSourceTypes
+ ? mapperData.GetDerivedSourceTypes()
+ : EmptyTypeArray;
+ }
- return mappingData.MapperData.GetDerivedTargetTypes();
+ private static ICollection GetDerivedTargetTypesIfNecessary(IMemberMapperData mapperData)
+ {
+ return mapperData.TargetCouldBePopulated()
+ ? mapperData.GetDerivedTargetTypes()
+ : EmptyTypeArray;
}
private static void AddDeclaredSourceTypeMappings(
@@ -122,23 +141,22 @@ private static void AddDeclaredSourceTypeMappings(
if (sourceValueCondition != null)
{
- derivedTypeMapping = Expression.Condition(
+ derivedTypeMapping = Condition(
sourceValueCondition,
derivedTypeMapping,
derivedTypeMapping.Type.ToDefaultExpression());
}
- var returnMappingResult = Expression.Return(declaredTypeMapperData.ReturnLabelTarget, derivedTypeMapping);
-
- declaredTypeHasUnconditionalTypePair = (condition == null);
+ var returnMappingResult = Return(declaredTypeMapperData.ReturnLabelTarget, derivedTypeMapping);
- if (declaredTypeHasUnconditionalTypePair)
+ if (condition == null)
{
+ declaredTypeHasUnconditionalTypePair = true;
derivedTypeMappingExpressions.Add(returnMappingResult);
return;
}
- var ifConditionThenMap = Expression.IfThen(condition, returnMappingResult);
+ var ifConditionThenMap = IfThen(condition, returnMappingResult);
derivedTypeMappingExpressions.Add(ifConditionThenMap);
}
@@ -157,7 +175,7 @@ private static Expression GetTypePairCondition(DerivedTypePair derivedTypePair,
var pairCondition = derivedTypePair.GetConditionOrNull(declaredTypeMapperData);
- return (condition != null) ? Expression.AndAlso(pairCondition, condition) : pairCondition;
+ return (condition != null) ? AndAlso(pairCondition, condition) : pairCondition;
}
private static Expression GetDerivedTypeSourceValue(
@@ -200,16 +218,11 @@ private static Expression GetDerivedTypeSourceValue(
}
private static void AddDerivedSourceTypeMappings(
- ICollection derivedSourceTypes,
+ IEnumerable derivedSourceTypes,
IObjectMappingData declaredTypeMappingData,
ICollection typedObjectVariables,
IList derivedTypeMappingExpressions)
{
- if (derivedSourceTypes.None())
- {
- return;
- }
-
var declaredTypeMapperData = declaredTypeMappingData.MapperData;
var insertionOffset = derivedTypeMappingExpressions.Count;
@@ -245,28 +258,19 @@ private static void AddDerivedSourceTypeMappings(
continue;
}
- var groupedTypePairs = derivedTypePairs
- .GroupBy(tp => tp.DerivedTargetType)
- .Project(group => new TypePairGroup(group))
- .OrderBy(tp => tp.DerivedTargetType, TypeComparer.MostToLeastDerived)
- .ToArray();
-
- var unconditionalDerivedTargetTypeMapping = groupedTypePairs
- .Filter(tpg => tpg.TypePairs.None(tp => tp.HasConfiguredCondition))
- .Project(tpg => new
- {
- tpg.DerivedTargetType,
- TypePairsCondition = GetTargetValidCheckOrNull(tpg.DerivedTargetType, declaredTypeMapperData)
- })
- .FirstOrDefault(d => d.TypePairsCondition == null);
-
- if (unconditionalDerivedTargetTypeMapping != null)
+ var hasUnconditionalDerivedTargetTypeMapping = HasUnconditionalDerivedTargetTypeMapping(
+ derivedTypePairs,
+ declaredTypeMapperData,
+ out var unconditionalDerivedTargetType,
+ out var groupedTypePairs);
+
+ if (hasUnconditionalDerivedTargetTypeMapping)
{
ifSourceVariableIsDerivedTypeThenMap = GetIfConditionThenMapExpression(
declaredTypeMappingData,
outerCondition,
derivedSourceCheck.TypedVariable,
- unconditionalDerivedTargetTypeMapping.DerivedTargetType);
+ unconditionalDerivedTargetType);
derivedTypeMappingExpressions.Insert(ifSourceVariableIsDerivedTypeThenMap, insertionOffset);
continue;
@@ -283,6 +287,38 @@ private static void AddDerivedSourceTypeMappings(
}
}
+ private static bool HasUnconditionalDerivedTargetTypeMapping(
+ IEnumerable derivedTypePairs,
+ IMemberMapperData declaredTypeMapperData,
+ out Type unconditionalDerivedTargetType,
+ out TypePairGroup[] groupedTypePairs)
+ {
+ groupedTypePairs = derivedTypePairs
+ .GroupBy(tp => tp.DerivedTargetType)
+ .Project(group => new TypePairGroup(group))
+ .OrderBy(tp => tp.DerivedTargetType, TypeComparer.MostToLeastDerived)
+ .ToArray();
+
+ var unconditionalTypePairs = groupedTypePairs
+ .Filter(tpg => tpg.TypePairs.None(tp => tp.HasConfiguredCondition));
+
+ foreach (var unconditionalTypePair in unconditionalTypePairs)
+ {
+ var typePairsCondition = GetTargetValidCheckOrNull(
+ unconditionalTypePair.DerivedTargetType,
+ declaredTypeMapperData);
+
+ if (typePairsCondition == null)
+ {
+ unconditionalDerivedTargetType = unconditionalTypePair.DerivedTargetType;
+ return true;
+ }
+ }
+
+ unconditionalDerivedTargetType = null;
+ return false;
+ }
+
private static void AddDerivedTargetTypeMappings(
IObjectMappingData declaredTypeMappingData,
IEnumerable derivedTargetTypes,
@@ -315,12 +351,12 @@ private static Expression GetIfConditionThenMapExpression(
{
var returnMappingResult = GetReturnMappingResultExpression(mappingData, sourceValue, targetType);
- if (returnMappingResult == Constants.EmptyExpression)
+ if (returnMappingResult == EmptyExpression)
{
- return Constants.EmptyExpression;
+ return EmptyExpression;
}
- var ifConditionThenMap = Expression.IfThen(condition, returnMappingResult);
+ var ifConditionThenMap = IfThen(condition, returnMappingResult);
return ifConditionThenMap;
}
@@ -332,12 +368,12 @@ private static Expression GetReturnMappingResultExpression(
{
var mapping = DerivedMappingFactory.GetDerivedTypeMapping(mappingData, sourceValue, targetType);
- if (mapping == Constants.EmptyExpression)
+ if (mapping == EmptyExpression)
{
- return Constants.EmptyExpression;
+ return EmptyExpression;
}
- var returnMappingResult = Expression.Return(mappingData.MapperData.ReturnLabelTarget, mapping);
+ var returnMappingResult = Return(mappingData.MapperData.ReturnLabelTarget, mapping);
return returnMappingResult;
}
@@ -371,13 +407,12 @@ private static Expression GetMapFromConditionOrDefaultExpression(
mappingExpressions.Add(mapToDeclaredTargetType);
- var ifSourceVariableIsDerivedTypeThenMap = Expression
- .IfThen(condition, Expression.Block(mappingExpressions));
+ var ifSourceVariableIsDerivedTypeThenMap = IfThen(condition, Block(mappingExpressions));
return ifSourceVariableIsDerivedTypeThenMap;
}
- private static IList GetTypePairsFor(
+ private static ICollection GetTypePairsFor(
Type derivedSourceType,
Type targetType,
IMemberMapperData mapperData)
@@ -392,7 +427,7 @@ private static IList GetTypePairsFor(
return GetTypePairsFor(pairTestMapperData, mapperData);
}
- private static IList GetTypePairsFor(IBasicMapperData pairTestMapperData, IMemberMapperData mapperData)
+ private static ICollection GetTypePairsFor(IBasicMapperData pairTestMapperData, IMemberMapperData mapperData)
{
var derivedTypePairs = mapperData.MapperContext.UserConfigurations
.DerivedTypes
@@ -411,7 +446,7 @@ private static Expression GetTypePairsCondition(
var pairConditions = conditionalPairs.Chain(
firstPair => firstPair.GetConditionOrNull(mapperData),
- (conditionSoFar, pair) => Expression.OrElse(
+ (conditionSoFar, pair) => OrElse(
conditionSoFar,
pair.GetConditionOrNull(mapperData)));
@@ -435,7 +470,7 @@ private static Expression AppendTargetValidCheckIfAppropriate(
return condition;
}
- condition = Expression.AndAlso(condition, targetIsValid);
+ condition = AndAlso(condition, targetIsValid);
return condition;
}
@@ -455,13 +490,13 @@ private static Expression GetTargetValidCheckOrNull(Type targetType, IMemberMapp
}
var targetIsNull = mapperData.TargetObject.GetIsDefaultComparison();
- var targetIsValid = Expression.OrElse(targetIsNull, targetIsOfDerivedType);
+ var targetIsValid = OrElse(targetIsNull, targetIsOfDerivedType);
return targetIsValid;
}
private static Expression GetTargetIsDerivedTypeCheck(Type targetType, IMemberMapperData mapperData)
- => Expression.TypeIs(mapperData.TargetObject, targetType);
+ => TypeIs(mapperData.TargetObject, targetType);
private static void Insert(this IList mappingExpressions, Expression mapping, int insertionOffset)
{
diff --git a/AgileMapper/ObjectPopulation/DictionaryMappingExpressionFactory.cs b/AgileMapper/ObjectPopulation/DictionaryMappingExpressionFactory.cs
index 19f249bbc..f84553f4c 100644
--- a/AgileMapper/ObjectPopulation/DictionaryMappingExpressionFactory.cs
+++ b/AgileMapper/ObjectPopulation/DictionaryMappingExpressionFactory.cs
@@ -56,7 +56,7 @@ private static IEnumerable GetAllTargetMembers(ObjectMapperData
return allTargetMembers;
}
- private static IEnumerable EnumerateAllTargetMembers(ObjectMapperData mapperData)
+ private static IEnumerable EnumerateAllTargetMembers(ObjectMapperData mapperData)
{
var sourceMembers = GlobalContext.Instance.MemberCache.GetSourceMembers(mapperData.SourceType);
var targetDictionaryMember = (DictionaryTargetMember)mapperData.TargetMember;
@@ -207,16 +207,15 @@ private static IEnumerable GetNestedFlattenedMembers(
.ToArray();
}
- private static DictionaryTargetMember[] GetConfiguredTargetMembers(
+ private static QualifiedMember[] GetConfiguredTargetMembers(
IEnumerable configuredDataSourceFactories,
- IList targetMembersFromSource)
+ IList targetMembersFromSource)
{
return configuredDataSourceFactories
.GroupBy(dsf => dsf.TargetDictionaryEntryMember.Name)
.Project(group =>
{
- var factory = group.First();
- var targetMember = factory.TargetDictionaryEntryMember;
+ QualifiedMember targetMember = group.First().TargetDictionaryEntryMember;
targetMember.IsCustom = targetMembersFromSource.None(
sourceMember => sourceMember.RegistrationName == targetMember.Name);
@@ -277,10 +276,12 @@ protected override Expression GetNullMappingFallbackValue(IMemberMapperData mapp
protected override IEnumerable GetObjectPopulation(MappingCreationContext context)
{
+ Expression population;
+
if (!context.MapperData.TargetMember.IsDictionary)
{
- yield return GetDictionaryPopulation(context.MappingData);
- yield break;
+ population = GetDictionaryPopulation(context.MappingData);
+ goto ReturnPopulation;
}
var assignmentFactory = GetDictionaryAssignmentFactoryOrNull(context, out var useAssignmentOnly);
@@ -291,11 +292,19 @@ protected override IEnumerable GetObjectPopulation(MappingCreationCo
yield break;
}
- var population = GetDictionaryPopulation(context.MappingData);
+ population = GetDictionaryPopulation(context.MappingData);
var assignment = assignmentFactory?.Invoke(context.MappingData);
- yield return assignment;
- yield return population;
+ if (assignment != null)
+ {
+ yield return assignment;
+ }
+
+ ReturnPopulation:
+ if (population != null)
+ {
+ yield return population;
+ }
}
private static Func GetDictionaryAssignmentFactoryOrNull(
diff --git a/AgileMapper/ObjectPopulation/Enumerables/Dictionaries/DictionaryPopulationBuilder.cs b/AgileMapper/ObjectPopulation/Enumerables/Dictionaries/DictionaryPopulationBuilder.cs
index e4a51e34e..df9c9545a 100644
--- a/AgileMapper/ObjectPopulation/Enumerables/Dictionaries/DictionaryPopulationBuilder.cs
+++ b/AgileMapper/ObjectPopulation/Enumerables/Dictionaries/DictionaryPopulationBuilder.cs
@@ -98,7 +98,7 @@ private Expression AssignDictionaryEntryFromKeyValuePair(
var targetEntryAssignmentBlock = (BlockExpression)targetEntryAssignment;
return Expression.Block(
- targetEntryAssignmentBlock.Variables.Prepend(keyVariable),
+ targetEntryAssignmentBlock.Variables.Append(keyVariable),
targetEntryAssignmentBlock.Expressions.Prepend(keyAssignment));
}
@@ -237,7 +237,7 @@ private Expression GetPopulation(
{
var elementMapping = loopData.GetElementMapping(dictionaryMappingData);
- if (dictionaryEntryMember.HasKey &&
+ if (dictionaryEntryMember.HasKey &&
dictionaryEntryMember.CheckExistingElementValue &&
dictionaryMappingData.MapperData.TargetCouldBePopulated())
{
@@ -256,14 +256,14 @@ private Expression GetPopulation(
IObjectMappingData mappingData)
{
var elementMapperData = new ChildMemberMapperData(dictionaryEntryMember, MapperData);
- var elementMappingData = mappingData.GetChildMappingData(elementMapperData);
var sourceMember = mappingData.MapperData.SourceMember;
var mappingDataSource = new AdHocDataSource(sourceMember, elementMapping);
var mappingDataSources = new DataSourceSet(elementMapperData, mappingDataSource);
- var memberPopulation = MemberPopulator.WithoutRegistration(elementMappingData, mappingDataSources);
- var populationExpression = memberPopulation.GetPopulation();
+ var populationExpression = MemberPopulator
+ .WithoutRegistration(mappingDataSources)
+ .GetPopulation();
return populationExpression;
}
diff --git a/AgileMapper/ObjectPopulation/Enumerables/Dictionaries/SourceObjectDictionaryPopulationLoopData.cs b/AgileMapper/ObjectPopulation/Enumerables/Dictionaries/SourceObjectDictionaryPopulationLoopData.cs
index fe7240217..cc40bd781 100644
--- a/AgileMapper/ObjectPopulation/Enumerables/Dictionaries/SourceObjectDictionaryPopulationLoopData.cs
+++ b/AgileMapper/ObjectPopulation/Enumerables/Dictionaries/SourceObjectDictionaryPopulationLoopData.cs
@@ -73,8 +73,8 @@ public Expression Adapt(LoopExpression loop)
DisposeEnumeratorIfNecessary);
return Expression.Block(
- new[] { _sourceEnumerableFound }.Append(enumerableLoopBlock.Variables),
- new[] { assignSourceEnumerableFound }.Append(enumerableLoopBlock.Expressions));
+ enumerableLoopBlock.Variables.Append(_sourceEnumerableFound),
+ enumerableLoopBlock.Expressions.Prepend(assignSourceEnumerableFound));
}
public static BinaryExpression GetSourceEnumerableFoundTest(
diff --git a/AgileMapper/ObjectPopulation/Enumerables/EnumerablePopulationBuilder.cs b/AgileMapper/ObjectPopulation/Enumerables/EnumerablePopulationBuilder.cs
index 04bc0a6f8..933a8e2d2 100644
--- a/AgileMapper/ObjectPopulation/Enumerables/EnumerablePopulationBuilder.cs
+++ b/AgileMapper/ObjectPopulation/Enumerables/EnumerablePopulationBuilder.cs
@@ -615,7 +615,7 @@ private static Expression GetValueCheckedElementMapping(
var mappingTryCatchBodyBlock = (BlockExpression)mappingTryCatch.Body;
mappingTryCatchBody = Expression.Block(
- mappingTryCatchBodyBlock.Variables.Prepend(valueVariable),
+ mappingTryCatchBodyBlock.Variables.Append(valueVariable),
existingElementValueCheck.Expressions.Append(mappingTryCatchBodyBlock.Expressions));
}
diff --git a/AgileMapper/ObjectPopulation/Enumerables/EnumerableTypeHelper.cs b/AgileMapper/ObjectPopulation/Enumerables/EnumerableTypeHelper.cs
index d5241e0e6..c5d5abc41 100644
--- a/AgileMapper/ObjectPopulation/Enumerables/EnumerableTypeHelper.cs
+++ b/AgileMapper/ObjectPopulation/Enumerables/EnumerableTypeHelper.cs
@@ -4,15 +4,16 @@ namespace AgileObjects.AgileMapper.ObjectPopulation.Enumerables
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
- using Extensions.Internal;
- using Members;
- using NetStandardPolyfills;
- using ReadableExpressions.Extensions;
#if NET35
using Microsoft.Scripting.Ast;
#else
using System.Linq.Expressions;
#endif
+ using Extensions.Internal;
+ using Members;
+ using NetStandardPolyfills;
+ using ReadableExpressions.Extensions;
+ using TypeConversion;
internal class EnumerableTypeHelper
{
@@ -198,6 +199,15 @@ private static bool ValueIsNotEnumerableInterface(Expression instance)
public Expression GetCountFor(Expression instance, Type countType = null)
=> instance.GetCount(countType, exp => CollectionInterfaceType);
+ public Expression GetNonZeroCountCheck(Expression enumerableAccess)
+ {
+ var enumerableCount = GetCountFor(enumerableAccess);
+ var zero = ToNumericConverter.Zero.GetConversionTo(enumerableCount.Type);
+ var countGreaterThanZero = Expression.GreaterThan(enumerableCount, zero);
+
+ return countGreaterThanZero;
+ }
+
public Type GetEmptyInstanceCreationFallbackType()
{
if (IsArray)
diff --git a/AgileMapper/ObjectPopulation/MappingCreationContext.cs b/AgileMapper/ObjectPopulation/MappingCreationContext.cs
index 43a388755..0e943913b 100644
--- a/AgileMapper/ObjectPopulation/MappingCreationContext.cs
+++ b/AgileMapper/ObjectPopulation/MappingCreationContext.cs
@@ -17,7 +17,7 @@ namespace AgileObjects.AgileMapper.ObjectPopulation
internal class MappingCreationContext
{
private bool _mapperDataHasRootEnumerableVariables;
- private List _memberMappingExpressions;
+ private IList _memberMappingExpressions;
public MappingCreationContext(IObjectMappingData mappingData)
{
@@ -62,11 +62,11 @@ private static Expression GetMapToNullConditionOrNull(IMemberMapperData mapperDa
public bool InstantiateLocalVariable { get; set; }
- public List GetMemberMappingExpressions()
+ public IList GetMemberMappingExpressions()
{
if (_memberMappingExpressions?.Count == MappingExpressions.Count)
{
- return _memberMappingExpressions ?? new List(0);
+ return _memberMappingExpressions ?? Enumerable.EmptyArray;
}
return _memberMappingExpressions = MappingExpressions.Filter(IsMemberMapping).ToList();
diff --git a/AgileMapper/ObjectPopulation/MappingExpressionFactoryBase.cs b/AgileMapper/ObjectPopulation/MappingExpressionFactoryBase.cs
index 430382e11..a73872320 100644
--- a/AgileMapper/ObjectPopulation/MappingExpressionFactoryBase.cs
+++ b/AgileMapper/ObjectPopulation/MappingExpressionFactoryBase.cs
@@ -103,14 +103,11 @@ protected virtual IEnumerable GetShortCircuitReturns(GotoExpression
private void AddPopulationsAndCallbacks(MappingCreationContext context)
{
context.MappingExpressions.AddUnlessNullOrEmpty(context.PreMappingCallback);
- context.MappingExpressions.AddRange(GetNonNullObjectPopulation(context));
+ context.MappingExpressions.AddRange(GetObjectPopulation(context));
context.MappingExpressions.AddRange(GetConfiguredToTargetDataSourceMappings(context));
context.MappingExpressions.AddUnlessNullOrEmpty(context.PostMappingCallback);
}
- private IEnumerable GetNonNullObjectPopulation(MappingCreationContext context)
- => GetObjectPopulation(context).WhereNotNull();
-
protected abstract IEnumerable GetObjectPopulation(MappingCreationContext context);
private IEnumerable GetConfiguredToTargetDataSourceMappings(MappingCreationContext context)
diff --git a/AgileMapper/TypeConversion/ToBoolConverter.cs b/AgileMapper/TypeConversion/ToBoolConverter.cs
index 406fa4a83..32da2d8cd 100644
--- a/AgileMapper/TypeConversion/ToBoolConverter.cs
+++ b/AgileMapper/TypeConversion/ToBoolConverter.cs
@@ -4,13 +4,13 @@ namespace AgileObjects.AgileMapper.TypeConversion
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
- using Extensions.Internal;
- using ReadableExpressions.Extensions;
#if NET35
using Microsoft.Scripting.Ast;
#else
using System.Linq.Expressions;
#endif
+ using Extensions.Internal;
+ using ReadableExpressions.Extensions;
internal struct ToBoolConverter : IValueConverter
{
diff --git a/AgileMapper/TypeConversion/ToCharacterConverter.cs b/AgileMapper/TypeConversion/ToCharacterConverter.cs
index 25a56f2ae..d147ac657 100644
--- a/AgileMapper/TypeConversion/ToCharacterConverter.cs
+++ b/AgileMapper/TypeConversion/ToCharacterConverter.cs
@@ -1,15 +1,14 @@
namespace AgileObjects.AgileMapper.TypeConversion
{
using System;
- using System.Linq;
- using Extensions.Internal;
- using NetStandardPolyfills;
- using ReadableExpressions.Extensions;
#if NET35
using Microsoft.Scripting.Ast;
#else
using System.Linq.Expressions;
#endif
+ using Extensions.Internal;
+ using NetStandardPolyfills;
+ using ReadableExpressions.Extensions;
internal struct ToCharacterConverter : IValueConverter
{
diff --git a/AgileMapper/TypeConversion/ToEnumConverter.cs b/AgileMapper/TypeConversion/ToEnumConverter.cs
index 4ae1e743f..08d1de9ce 100644
--- a/AgileMapper/TypeConversion/ToEnumConverter.cs
+++ b/AgileMapper/TypeConversion/ToEnumConverter.cs
@@ -4,16 +4,16 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
- using Configuration;
- using Extensions;
- using Extensions.Internal;
- using NetStandardPolyfills;
- using ReadableExpressions.Extensions;
#if NET35
using Microsoft.Scripting.Ast;
#else
using System.Linq.Expressions;
#endif
+ using Configuration;
+ using Extensions;
+ using Extensions.Internal;
+ using NetStandardPolyfills;
+ using ReadableExpressions.Extensions;
internal class ToEnumConverter : IValueConverter
{
@@ -495,17 +495,8 @@ private static Expression GetStringValueConversion(
numericConversion,
nameMatchingConversion);
- var valueIsNullOrEmpty = Expression.Call(
-#if NET35
- typeof(StringExtensions)
-#else
- typeof(string)
-#endif
- .GetPublicStaticMethod("IsNullOrWhiteSpace"),
- sourceValue);
-
var convertedValueOrDefault = Expression.Condition(
- valueIsNullOrEmpty,
+ StringExpressionExtensions.GetIsNullOrWhiteSpaceCall(sourceValue),
fallbackValue,
numericOrNameConversion);
diff --git a/AgileMapper/TypeConversion/ToFormattedStringConverter.cs b/AgileMapper/TypeConversion/ToFormattedStringConverter.cs
index ab9f2fbab..58ec61490 100644
--- a/AgileMapper/TypeConversion/ToFormattedStringConverter.cs
+++ b/AgileMapper/TypeConversion/ToFormattedStringConverter.cs
@@ -2,14 +2,14 @@
{
using System;
using System.Reflection;
- using Configuration;
- using Extensions.Internal;
- using ReadableExpressions.Extensions;
#if NET35
using Microsoft.Scripting.Ast;
#else
using System.Linq.Expressions;
#endif
+ using Configuration;
+ using Extensions.Internal;
+ using ReadableExpressions.Extensions;
internal class ToFormattedStringConverter : IValueConverter
{
@@ -28,7 +28,7 @@ public ToFormattedStringConverter(Type sourceValueType, string formattingString)
}
_sourceValueType = sourceValueType;
- _formattingString = formattingString.ToConstantExpression(typeof(string));
+ _formattingString = formattingString.ToConstantExpression();
}
public bool CanConvert(Type nonNullableSourceType, Type nonNullableTargetType)
diff --git a/AgileMapper/TypeConversion/ToNumericConverter.cs b/AgileMapper/TypeConversion/ToNumericConverter.cs
index 785a27b80..6f20a9e4b 100644
--- a/AgileMapper/TypeConversion/ToNumericConverter.cs
+++ b/AgileMapper/TypeConversion/ToNumericConverter.cs
@@ -2,14 +2,14 @@
{
using System;
using System.Linq;
- using Extensions.Internal;
- using NetStandardPolyfills;
- using ReadableExpressions.Extensions;
#if NET35
using Microsoft.Scripting.Ast;
#else
using System.Linq.Expressions;
#endif
+ using Extensions.Internal;
+ using NetStandardPolyfills;
+ using ReadableExpressions.Extensions;
internal class ToNumericConverter : TryParseConverter
{