From 484a298e173f0037c202c71ae6a6ca711109bb10 Mon Sep 17 00:00:00 2001 From: Mark Quennell Date: Mon, 8 Jul 2019 16:11:12 +0100 Subject: [PATCH 1/2] Summary of changes: - Added code to TypeMapFactory+ConstructorMap to check for valid ForCtorParam entries to match against a Constructor #3159 --- src/AutoMapper/ApiCompatBaseline.txt | 4 +- .../CtorParamConfigurationExpression.cs | 5 + .../ICtorParameterConfiguration.cs | 1 + .../Configuration/ITypeMapConfiguration.cs | 2 + .../Configuration/MappingExpressionBase.cs | 2 + src/AutoMapper/ConstructorMap.cs | 10 +- src/AutoMapper/ProfileMap.cs | 38 ++++-- src/AutoMapper/TypeMapFactory.cs | 4 +- src/UnitTests/Constructors.cs | 129 ++++++++++++++++++ 9 files changed, 179 insertions(+), 16 deletions(-) diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index bbe662d9e1..07bf40cdb1 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -1,6 +1,7 @@ Compat issues with assembly AutoMapper: MembersMustExist : Member 'AutoMapper.AutoMapperConfigurationException.PropertyMap.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'AutoMapper.AutoMapperConfigurationException.PropertyMap.set(AutoMapper.PropertyMap)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'AutoMapper.ConstructorMap..ctor(System.Reflection.ConstructorInfo, AutoMapper.TypeMap)' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.CtorParamConfigurationExpression' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.IConfigurationProvider.Features' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.IConfigurationProvider.Features.get()' is present in the implementation but not in the contract. @@ -156,6 +157,7 @@ MembersMustExist : Member 'AutoMapper.Configuration.IProfileConfiguration.Valida InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.Configuration.IPropertyMapConfiguration.SourceExpression' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.Configuration.IPropertyMapConfiguration.GetDestinationExpression()' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.Configuration.IPropertyMapConfiguration.SourceExpression.get()' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.Configuration.ITypeMapConfiguration.GetCtorParameterConfigs()' is present in the implementation but not in the contract. MembersMustExist : Member 'AutoMapper.Configuration.MapperConfigurationExpression.AddProfiles(System.Collections.Generic.IEnumerable)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'AutoMapper.Configuration.MapperConfigurationExpression.AddProfiles(System.Collections.Generic.IEnumerable)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'AutoMapper.Configuration.MapperConfigurationExpression.AddProfiles(System.Collections.Generic.IEnumerable)' does not exist in the implementation but it does exist in the contract. @@ -191,4 +193,4 @@ MembersMustExist : Member 'AutoMapper.QueryableExtensions.ProjectionExpression.T MembersMustExist : Member 'AutoMapper.QueryableExtensions.ProjectionExpression.To(System.Collections.Generic.IDictionary, System.Linq.Expressions.Expression>[])' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'AutoMapper.QueryableExtensions.ProjectionExpression.To(System.Object)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'AutoMapper.QueryableExtensions.ProjectionExpression.To(System.Object, System.String[])' does not exist in the implementation but it does exist in the contract. -Total Issues: 192 +Total Issues: 194 diff --git a/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs b/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs index 65d4053551..cb1231a065 100644 --- a/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs @@ -43,5 +43,10 @@ public void Configure(TypeMap typeMap) action(parameter); } } + + public bool CheckCtorParamName(string paramName) + { + return _ctorParamName == paramName; + } } } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/ICtorParameterConfiguration.cs b/src/AutoMapper/Configuration/ICtorParameterConfiguration.cs index 59e126b4ce..67c87019fb 100644 --- a/src/AutoMapper/Configuration/ICtorParameterConfiguration.cs +++ b/src/AutoMapper/Configuration/ICtorParameterConfiguration.cs @@ -3,5 +3,6 @@ public interface ICtorParameterConfiguration { void Configure(TypeMap typeMap); + bool CheckCtorParamName(string paramName); } } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/ITypeMapConfiguration.cs b/src/AutoMapper/Configuration/ITypeMapConfiguration.cs index bb03c14a95..7a43d29644 100644 --- a/src/AutoMapper/Configuration/ITypeMapConfiguration.cs +++ b/src/AutoMapper/Configuration/ITypeMapConfiguration.cs @@ -1,10 +1,12 @@ using System; +using System.Collections.Generic; namespace AutoMapper.Configuration { public interface ITypeMapConfiguration { void Configure(TypeMap typeMap); + IList GetCtorParameterConfigs(); Type SourceType { get; } Type DestinationType { get; } bool IsOpenGeneric { get; } diff --git a/src/AutoMapper/Configuration/MappingExpressionBase.cs b/src/AutoMapper/Configuration/MappingExpressionBase.cs index 150bd171ac..2cd43f6f10 100644 --- a/src/AutoMapper/Configuration/MappingExpressionBase.cs +++ b/src/AutoMapper/Configuration/MappingExpressionBase.cs @@ -180,6 +180,8 @@ protected IPropertyMapConfiguration GetDestinationMemberConfiguration(MemberInfo MemberConfigurations.FirstOrDefault(m => m.DestinationMember.Name == destinationMember.Name); protected abstract void IgnoreDestinationMember(MemberInfo property, bool ignorePaths = true); + + public IList GetCtorParameterConfigs() => CtorParamConfigurations; } public abstract class MappingExpressionBase diff --git a/src/AutoMapper/ConstructorMap.cs b/src/AutoMapper/ConstructorMap.cs index 99e2595f7c..a537571b13 100644 --- a/src/AutoMapper/ConstructorMap.cs +++ b/src/AutoMapper/ConstructorMap.cs @@ -4,6 +4,7 @@ using System.Linq.Expressions; using System.Reflection; using AutoMapper.Execution; +using AutoMapper.Configuration; using AutoMapper.QueryableExtensions; using AutoMapper.QueryableExtensions.Impl; @@ -14,15 +15,17 @@ namespace AutoMapper public class ConstructorMap { private readonly IList _ctorParams = new List(); + private readonly IList _ctorConfigs = new List(); public ConstructorInfo Ctor { get; } public TypeMap TypeMap { get; } public IEnumerable CtorParams => _ctorParams; - public ConstructorMap(ConstructorInfo ctor, TypeMap typeMap) + public ConstructorMap(ConstructorInfo ctor, TypeMap typeMap, ProfileMap options) { Ctor = ctor; TypeMap = typeMap; + _ctorConfigs = options.GetCtorParameterConfigs(typeMap); } private static readonly IExpressionResultConverter[] ExpressionResultConverters = @@ -54,5 +57,10 @@ public void AddParameter(ParameterInfo parameter, MemberInfo[] resolvers, bool c { _ctorParams.Add(new ConstructorParameterMap(TypeMap, parameter, resolvers, canResolve)); } + + public bool ContainsCtorParameterConfig(string paramName) + { + return _ctorConfigs.Any(c => c.CheckCtorParamName(paramName)); + } } } diff --git a/src/AutoMapper/ProfileMap.cs b/src/AutoMapper/ProfileMap.cs index f20a551580..793c6be7af 100644 --- a/src/AutoMapper/ProfileMap.cs +++ b/src/AutoMapper/ProfileMap.cs @@ -32,8 +32,8 @@ public ProfileMap(IProfileConfiguration profile, IConfiguration configuration) EnableNullPropagationForQueryMapping = profile.EnableNullPropagationForQueryMapping ?? configuration?.EnableNullPropagationForQueryMapping ?? false; ConstructorMappingEnabled = profile.ConstructorMappingEnabled ?? configuration?.ConstructorMappingEnabled ?? true; ShouldMapField = profile.ShouldMapField ?? configuration?.ShouldMapField ?? (p => p.IsPublic()); - ShouldMapProperty = profile.ShouldMapProperty ?? configuration?.ShouldMapProperty ?? (p => p.IsPublic()); - ShouldMapMethod = profile.ShouldMapMethod ?? configuration?.ShouldMapMethod ?? (p => true); + ShouldMapProperty = profile.ShouldMapProperty ?? configuration?.ShouldMapProperty ?? (p => p.IsPublic()); + ShouldMapMethod = profile.ShouldMapMethod ?? configuration?.ShouldMapMethod ?? (p => true); ShouldUseConstructor = profile.ShouldUseConstructor ?? configuration?.ShouldUseConstructor ?? (c => true); ValueTransformers = profile.ValueTransformers.Concat(configuration?.ValueTransformers ?? Enumerable.Empty()).ToArray(); @@ -75,10 +75,10 @@ public ProfileMap(IProfileConfiguration profile, IConfiguration configuration) public bool EnableNullPropagationForQueryMapping { get; } public string Name { get; } public Func ShouldMapField { get; } - public Func ShouldMapProperty { get; } - public Func ShouldMapMethod { get; } + public Func ShouldMapProperty { get; } + public Func ShouldMapMethod { get; } public Func ShouldUseConstructor { get; } - + public IEnumerable> AllPropertyMapActions { get; } public IEnumerable> AllTypeMapActions { get; } public IEnumerable GlobalIgnores { get; } @@ -156,7 +156,7 @@ private void Configure(TypeMap typeMap, IConfigurationProvider configurationProv } ApplyBaseMaps(typeMap, typeMap, configurationProvider); - ApplyDerivedMaps(typeMap, typeMap, configurationProvider); + ApplyDerivedMaps(typeMap, typeMap, configurationProvider); ApplyMemberMaps(typeMap, configurationProvider); } @@ -209,9 +209,9 @@ private void ApplyBaseMaps(TypeMap derivedMap, TypeMap currentMap, IConfiguratio } private void ApplyMemberMaps(TypeMap mainMap, IConfigurationProvider configurationProvider) - { - AddMemberMaps(mainMap.IncludedMembers, mainMap, configurationProvider); - AddMemberMaps(mainMap.GetUntypedIncludedMembers(), mainMap, configurationProvider); + { + AddMemberMaps(mainMap.IncludedMembers, mainMap, configurationProvider); + AddMemberMaps(mainMap.GetUntypedIncludedMembers(), mainMap, configurationProvider); } private void AddMemberMaps(LambdaExpression[] includedMembers, TypeMap mainMap, IConfigurationProvider configurationProvider) @@ -226,15 +226,29 @@ private void ApplyDerivedMaps(TypeMap baseMap, TypeMap typeMap, IConfigurationPr { foreach (var derivedMap in configurationProvider.GetIncludedTypeMaps(typeMap.IncludedDerivedTypes)) { - derivedMap.IncludeBaseTypes(typeMap.SourceType, typeMap.DestinationType); + derivedMap.IncludeBaseTypes(typeMap.SourceType, typeMap.DestinationType); derivedMap.AddInheritedMap(baseMap); ApplyDerivedMaps(baseMap, derivedMap, configurationProvider); } } - } + public IList GetCtorParameterConfigs(TypeMap typeMap) + { + var list = new List(); + foreach(var config in _typeMapConfigs.Where(c => c.SourceType == typeMap.SourceType && c.DestinationType == typeMap.DestinationType)) + { + if (!(config is MappingExpressionBase mappingExpression)) + continue; + + list.AddRange(mappingExpression.GetCtorParameterConfigs()); + } + return list; + } + + } + public readonly struct IncludedMember - { + { public IncludedMember(TypeMap typeMap, LambdaExpression memberExpression) { TypeMap = typeMap; diff --git a/src/AutoMapper/TypeMapFactory.cs b/src/AutoMapper/TypeMapFactory.cs index 36c4b87a04..2db40634c1 100644 --- a/src/AutoMapper/TypeMapFactory.cs +++ b/src/AutoMapper/TypeMapFactory.cs @@ -53,14 +53,14 @@ private bool MapDestinationCtorToSource(TypeMap typeMap, ConstructorInfo destCto if (ctorParameters.Length == 0 || !options.ConstructorMappingEnabled) return false; - var ctorMap = new ConstructorMap(destCtor, typeMap); + var ctorMap = new ConstructorMap(destCtor, typeMap, options); foreach (var parameter in ctorParameters) { var resolvers = new LinkedList(); var canResolve = MapDestinationPropertyToSource(options, sourceTypeInfo, destCtor.DeclaringType, parameter.GetType(), parameter.Name, resolvers); - if(!canResolve && parameter.IsOptional) + if((!canResolve && parameter.IsOptional) || ctorMap.ContainsCtorParameterConfig(parameter.Name)) { canResolve = true; } diff --git a/src/UnitTests/Constructors.cs b/src/UnitTests/Constructors.cs index ed2a61b68d..473f8f8ab3 100644 --- a/src/UnitTests/Constructors.cs +++ b/src/UnitTests/Constructors.cs @@ -1609,4 +1609,133 @@ public void Should_redirect_value() dest.Value1.ShouldBeNull(); } } + + public class When_configuring_ctor_param_members_without_source_property_1 : AutoMapperSpecBase + { + public class Source + { + public string Result { get; } + + public Source(string result) + { + Result = result; + } + } + + public class Dest + { + public string Result{ get; } + public dynamic Details { get; } + + public Dest(string result, DestInner1 inner1) + { + Result = result; + Details = inner1; + } + public Dest(string result, DestInner2 inner2) + { + Result = result; + Details = inner2; + } + + public class DestInner1 + { + public int Value { get; } + + public DestInner1(int value) + { + Value = value; + } + } + + public class DestInner2 + { + public int Value { get; } + + public DestInner2(int value) + { + Value = value; + } + } + } + + protected override MapperConfiguration Configuration { get; } = new MapperConfiguration(config => + { + config.CreateMap() + .ForCtorParam("inner1", cfg => cfg.MapFrom(_ => new Dest.DestInner1(100))); + }); + + [Fact] + public void Should_redirect_value() + { + var dest = Mapper.Map(new Source("Success")); + + dest.ShouldNotBeNull(); + } + } + + public class When_configuring_ctor_param_members_without_source_property_2 : AutoMapperSpecBase + { + public class Source + { + public string Result { get; } + + public Source(string result) + { + Result = result; + } + } + + public class Dest + { + public string Result{ get; } + public dynamic Details { get; } + + public Dest(string result, DestInner1 inner1) + { + Result = result; + Details = inner1; + } + public Dest(string result, DestInner2 inner2) + { + Result = result; + Details = inner2; + } + + public class DestInner1 + { + public int Value { get; } + + public DestInner1(int value) + { + Value = value; + } + } + + public class DestInner2 + { + public int Value { get; } + + public DestInner2(int value) + { + Value = value; + } + } + } + + protected override MapperConfiguration Configuration { get; } = new MapperConfiguration(config => + { + config.CreateMap() + .ForCtorParam("inner2", cfg => cfg.MapFrom(_ => new Dest.DestInner2(100))); + }); + + [Fact] + public void Should_redirect_value() + { + var dest = Mapper.Map(new Source("Success")); + + dest.ShouldNotBeNull(); + } + } + } From cb4d5c07c4c03c33accc15e58226d7dfb9825d9e Mon Sep 17 00:00:00 2001 From: Mark Quennell Date: Tue, 9 Jul 2019 09:56:51 +0100 Subject: [PATCH 2/2] After discussion with Lucian, I have moved MapDestinationCtorToSource from TypeMapFactory to MappingExpressionBase.Configure. --- src/AutoMapper/ApiCompatBaseline.txt | 4 +- .../Configuration/ITypeMapConfiguration.cs | 1 - .../Configuration/MappingExpressionBase.cs | 54 +++++++++++++++-- src/AutoMapper/ConstructorMap.cs | 9 +-- src/AutoMapper/ProfileMap.cs | 13 ---- src/AutoMapper/TypeMapFactory.cs | 60 +++++++++---------- 6 files changed, 82 insertions(+), 59 deletions(-) diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index 07bf40cdb1..bbe662d9e1 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -1,7 +1,6 @@ Compat issues with assembly AutoMapper: MembersMustExist : Member 'AutoMapper.AutoMapperConfigurationException.PropertyMap.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'AutoMapper.AutoMapperConfigurationException.PropertyMap.set(AutoMapper.PropertyMap)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'AutoMapper.ConstructorMap..ctor(System.Reflection.ConstructorInfo, AutoMapper.TypeMap)' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.CtorParamConfigurationExpression' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.IConfigurationProvider.Features' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.IConfigurationProvider.Features.get()' is present in the implementation but not in the contract. @@ -157,7 +156,6 @@ MembersMustExist : Member 'AutoMapper.Configuration.IProfileConfiguration.Valida InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.Configuration.IPropertyMapConfiguration.SourceExpression' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.Configuration.IPropertyMapConfiguration.GetDestinationExpression()' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.Configuration.IPropertyMapConfiguration.SourceExpression.get()' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.Configuration.ITypeMapConfiguration.GetCtorParameterConfigs()' is present in the implementation but not in the contract. MembersMustExist : Member 'AutoMapper.Configuration.MapperConfigurationExpression.AddProfiles(System.Collections.Generic.IEnumerable)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'AutoMapper.Configuration.MapperConfigurationExpression.AddProfiles(System.Collections.Generic.IEnumerable)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'AutoMapper.Configuration.MapperConfigurationExpression.AddProfiles(System.Collections.Generic.IEnumerable)' does not exist in the implementation but it does exist in the contract. @@ -193,4 +191,4 @@ MembersMustExist : Member 'AutoMapper.QueryableExtensions.ProjectionExpression.T MembersMustExist : Member 'AutoMapper.QueryableExtensions.ProjectionExpression.To(System.Collections.Generic.IDictionary, System.Linq.Expressions.Expression>[])' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'AutoMapper.QueryableExtensions.ProjectionExpression.To(System.Object)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'AutoMapper.QueryableExtensions.ProjectionExpression.To(System.Object, System.String[])' does not exist in the implementation but it does exist in the contract. -Total Issues: 194 +Total Issues: 192 diff --git a/src/AutoMapper/Configuration/ITypeMapConfiguration.cs b/src/AutoMapper/Configuration/ITypeMapConfiguration.cs index 7a43d29644..92f60f073b 100644 --- a/src/AutoMapper/Configuration/ITypeMapConfiguration.cs +++ b/src/AutoMapper/Configuration/ITypeMapConfiguration.cs @@ -6,7 +6,6 @@ namespace AutoMapper.Configuration public interface ITypeMapConfiguration { void Configure(TypeMap typeMap); - IList GetCtorParameterConfigs(); Type SourceType { get; } Type DestinationType { get; } bool IsOpenGeneric { get; } diff --git a/src/AutoMapper/Configuration/MappingExpressionBase.cs b/src/AutoMapper/Configuration/MappingExpressionBase.cs index 2cd43f6f10..ab397ec59a 100644 --- a/src/AutoMapper/Configuration/MappingExpressionBase.cs +++ b/src/AutoMapper/Configuration/MappingExpressionBase.cs @@ -40,7 +40,7 @@ protected MappingExpressionBase(MemberList memberList, TypePair types) public void Configure(TypeMap typeMap) { - foreach(var destProperty in typeMap.DestinationTypeDetails.PublicWriteAccessors) + foreach (var destProperty in typeMap.DestinationTypeDetails.PublicWriteAccessors) { var attrs = destProperty.GetCustomAttributes(true); if(attrs.Any(x => x is IgnoreMapAttribute)) @@ -58,7 +58,20 @@ public void Configure(TypeMap typeMap) } } - foreach(var action in TypeMapActions) + var destTypeInfo = typeMap.DestinationTypeDetails; + if (!typeMap.DestinationType.IsAbstract()) + { + foreach (var destCtor in destTypeInfo.Constructors.OrderByDescending(ci => ci.GetParameters().Length)) + { + if (MapDestinationCtorToSource(typeMap, destCtor, typeMap.SourceTypeDetails, typeMap.Profile)) + { + break; + } + } + } + + + foreach (var action in TypeMapActions) { action(typeMap); } @@ -100,6 +113,41 @@ public void Configure(TypeMap typeMap) } } + private bool MapDestinationCtorToSource(TypeMap typeMap, ConstructorInfo destCtor, TypeDetails sourceTypeInfo, ProfileMap options) + { + var ctorParameters = destCtor.GetParameters(); + + if (ctorParameters.Length == 0 || !options.ConstructorMappingEnabled) + return false; + + var ctorMap = new ConstructorMap(destCtor, typeMap); + + foreach (var parameter in ctorParameters) + { + var resolvers = new LinkedList(); + + var canResolve = MapDestinationPropertyToSource(options, sourceTypeInfo, destCtor.DeclaringType, parameter.GetType(), parameter.Name, resolvers); + if ((!canResolve && parameter.IsOptional) || CtorParamConfigurations.Any(c => c.CheckCtorParamName(parameter.Name))) + { + canResolve = true; + } + ctorMap.AddParameter(parameter, resolvers.ToArray(), canResolve); + } + + typeMap.ConstructorMap = ctorMap; + + return ctorMap.CanResolve; + } + + private bool MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourceTypeInfo, Type destType, Type destMemberType, string destMemberInfo, LinkedList members) + { + if (string.IsNullOrEmpty(destMemberInfo)) + { + return false; + } + return options.MemberConfigurations.Any(_ => _.MapDestinationPropertyToSource(options, sourceTypeInfo, destType, destMemberType, destMemberInfo, members)); + } + protected IEnumerable MapToSourceMembers() => MemberConfigurations.Where(m => m.SourceExpression != null && m.SourceExpression.Body == m.SourceExpression.Parameters[0]); @@ -180,8 +228,6 @@ protected IPropertyMapConfiguration GetDestinationMemberConfiguration(MemberInfo MemberConfigurations.FirstOrDefault(m => m.DestinationMember.Name == destinationMember.Name); protected abstract void IgnoreDestinationMember(MemberInfo property, bool ignorePaths = true); - - public IList GetCtorParameterConfigs() => CtorParamConfigurations; } public abstract class MappingExpressionBase diff --git a/src/AutoMapper/ConstructorMap.cs b/src/AutoMapper/ConstructorMap.cs index a537571b13..a11e926da6 100644 --- a/src/AutoMapper/ConstructorMap.cs +++ b/src/AutoMapper/ConstructorMap.cs @@ -15,17 +15,15 @@ namespace AutoMapper public class ConstructorMap { private readonly IList _ctorParams = new List(); - private readonly IList _ctorConfigs = new List(); public ConstructorInfo Ctor { get; } public TypeMap TypeMap { get; } public IEnumerable CtorParams => _ctorParams; - public ConstructorMap(ConstructorInfo ctor, TypeMap typeMap, ProfileMap options) + public ConstructorMap(ConstructorInfo ctor, TypeMap typeMap) { Ctor = ctor; TypeMap = typeMap; - _ctorConfigs = options.GetCtorParameterConfigs(typeMap); } private static readonly IExpressionResultConverter[] ExpressionResultConverters = @@ -57,10 +55,5 @@ public void AddParameter(ParameterInfo parameter, MemberInfo[] resolvers, bool c { _ctorParams.Add(new ConstructorParameterMap(TypeMap, parameter, resolvers, canResolve)); } - - public bool ContainsCtorParameterConfig(string paramName) - { - return _ctorConfigs.Any(c => c.CheckCtorParamName(paramName)); - } } } diff --git a/src/AutoMapper/ProfileMap.cs b/src/AutoMapper/ProfileMap.cs index 793c6be7af..b2c65db688 100644 --- a/src/AutoMapper/ProfileMap.cs +++ b/src/AutoMapper/ProfileMap.cs @@ -232,19 +232,6 @@ private void ApplyDerivedMaps(TypeMap baseMap, TypeMap typeMap, IConfigurationPr } } - public IList GetCtorParameterConfigs(TypeMap typeMap) - { - var list = new List(); - foreach(var config in _typeMapConfigs.Where(c => c.SourceType == typeMap.SourceType && c.DestinationType == typeMap.DestinationType)) - { - if (!(config is MappingExpressionBase mappingExpression)) - continue; - - list.AddRange(mappingExpression.GetCtorParameterConfigs()); - } - return list; - } - } public readonly struct IncludedMember diff --git a/src/AutoMapper/TypeMapFactory.cs b/src/AutoMapper/TypeMapFactory.cs index 2db40634c1..3020272849 100644 --- a/src/AutoMapper/TypeMapFactory.cs +++ b/src/AutoMapper/TypeMapFactory.cs @@ -24,52 +24,52 @@ public TypeMap CreateTypeMap(Type sourceType, Type destinationType, ProfileMap o typeMap.AddPropertyMap(destProperty, resolvers); } } - if (!destinationType.IsAbstract()) - { - foreach (var destCtor in destTypeInfo.Constructors.OrderByDescending(ci => ci.GetParameters().Length)) - { - if (MapDestinationCtorToSource(typeMap, destCtor, sourceTypeInfo, options)) - { - break; - } - } - } + //if (!destinationType.IsAbstract()) + //{ + // foreach (var destCtor in destTypeInfo.Constructors.OrderByDescending(ci => ci.GetParameters().Length)) + // { + // if (MapDestinationCtorToSource(typeMap, destCtor, sourceTypeInfo, options)) + // { + // break; + // } + // } + //} return typeMap; } private bool MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourceTypeInfo, Type destType, Type destMemberType, string destMemberInfo, LinkedList members) { - if(string.IsNullOrEmpty(destMemberInfo)) + if (string.IsNullOrEmpty(destMemberInfo)) { return false; } return options.MemberConfigurations.Any(_ => _.MapDestinationPropertyToSource(options, sourceTypeInfo, destType, destMemberType, destMemberInfo, members)); } - private bool MapDestinationCtorToSource(TypeMap typeMap, ConstructorInfo destCtor, TypeDetails sourceTypeInfo, ProfileMap options) - { - var ctorParameters = destCtor.GetParameters(); + //private bool MapDestinationCtorToSource(TypeMap typeMap, ConstructorInfo destCtor, TypeDetails sourceTypeInfo, ProfileMap options) + //{ + // var ctorParameters = destCtor.GetParameters(); - if (ctorParameters.Length == 0 || !options.ConstructorMappingEnabled) - return false; + // if (ctorParameters.Length == 0 || !options.ConstructorMappingEnabled) + // return false; - var ctorMap = new ConstructorMap(destCtor, typeMap, options); + // var ctorMap = new ConstructorMap(destCtor, typeMap, options); - foreach (var parameter in ctorParameters) - { - var resolvers = new LinkedList(); + // foreach (var parameter in ctorParameters) + // { + // var resolvers = new LinkedList(); - var canResolve = MapDestinationPropertyToSource(options, sourceTypeInfo, destCtor.DeclaringType, parameter.GetType(), parameter.Name, resolvers); - if((!canResolve && parameter.IsOptional) || ctorMap.ContainsCtorParameterConfig(parameter.Name)) - { - canResolve = true; - } - ctorMap.AddParameter(parameter, resolvers.ToArray(), canResolve); - } + // var canResolve = MapDestinationPropertyToSource(options, sourceTypeInfo, destCtor.DeclaringType, parameter.GetType(), parameter.Name, resolvers); + // if((!canResolve && parameter.IsOptional) || ctorMap.ContainsCtorParameterConfig(parameter.Name)) + // { + // canResolve = true; + // } + // ctorMap.AddParameter(parameter, resolvers.ToArray(), canResolve); + // } - typeMap.ConstructorMap = ctorMap; + // typeMap.ConstructorMap = ctorMap; - return ctorMap.CanResolve; - } + // return ctorMap.CanResolve; + //} } } \ No newline at end of file