Skip to content

Commit f30871e

Browse files
committed
enable ForAllMaps to work with ForCtorParam
1 parent 555db84 commit f30871e

File tree

4 files changed

+76
-45
lines changed

4 files changed

+76
-45
lines changed

src/AutoMapper/ApiCompatBaseline.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ InterfacesShouldHaveSameMembers : Interface member 'public TDestination AutoMapp
2727
InterfacesShouldHaveSameMembers : Interface member 'public TDestination AutoMapper.IRuntimeMapper.Map<TSource, TDestination>(TSource, TDestination, System.Action<AutoMapper.IMappingOperationOptions<TSource, TDestination>>)' is present in the implementation but not in the contract.
2828
CannotChangeAttribute : Attribute 'System.Runtime.CompilerServices.IteratorStateMachineAttribute' on 'AutoMapper.MapperConfiguration.GetIncludedTypeMaps(System.Collections.Generic.IEnumerable<AutoMapper.TypePair>)' changed from '[IteratorStateMachineAttribute(typeof(MapperConfiguration.<GetIncludedTypeMaps>d__69))]' in the contract to '[IteratorStateMachineAttribute(typeof(MapperConfiguration.<GetIncludedTypeMaps>d__72))]' in the implementation.
2929
TypesMustExist : Type 'AutoMapper.MemberFinderVisitor' does not exist in the implementation but it does exist in the contract.
30+
MembersMustExist : Member 'public System.Boolean AutoMapper.ProfileMap.MapDestinationCtorToSource(AutoMapper.TypeMap, System.Reflection.ConstructorInfo, AutoMapper.TypeDetails, System.Collections.Generic.List<AutoMapper.Configuration.ICtorParameterConfiguration>)' does not exist in the implementation but it does exist in the contract.
3031
MembersMustExist : Member 'public System.Collections.Generic.IEnumerable<System.Reflection.MemberInfo> AutoMapper.PropertyMap.SourceMembers.get()' does not exist in the implementation but it does exist in the contract.
3132
MembersMustExist : Member 'public System.Boolean AutoMapper.PropertyMap.UseDestinationValue.get()' does not exist in the implementation but it does exist in the contract.
3233
MembersMustExist : Member 'public void AutoMapper.PropertyMap.UseDestinationValue.set(System.Boolean)' does not exist in the implementation but it does exist in the contract.
@@ -63,4 +64,4 @@ MembersMustExist : Member 'public System.Boolean AutoMapper.QueryableExtensions.
6364
MembersMustExist : Member 'public System.Boolean AutoMapper.QueryableExtensions.Impl.MemberResolverExpressionResultConverter.CanGetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.PropertyMap)' does not exist in the implementation but it does exist in the contract.
6465
MembersMustExist : Member 'public AutoMapper.QueryableExtensions.ExpressionResolutionResult AutoMapper.QueryableExtensions.Impl.MemberResolverExpressionResultConverter.GetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.ConstructorParameterMap)' does not exist in the implementation but it does exist in the contract.
6566
MembersMustExist : Member 'public AutoMapper.QueryableExtensions.ExpressionResolutionResult AutoMapper.QueryableExtensions.Impl.MemberResolverExpressionResultConverter.GetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.PropertyMap, AutoMapper.QueryableExtensions.LetPropertyMaps)' does not exist in the implementation but it does exist in the contract.
66-
Total Issues: 64
67+
Total Issues: 65

src/AutoMapper/Configuration/MappingExpressionBase.cs

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ public void Configure(TypeMap typeMap)
4242
{
4343
foreach(var destProperty in typeMap.DestinationTypeDetails.PublicWriteAccessors)
4444
{
45-
var attrs = destProperty.GetCustomAttributes(true);
46-
if(attrs.Any(x => x is IgnoreMapAttribute))
45+
if(destProperty.Has<IgnoreMapAttribute>())
4746
{
4847
IgnoreDestinationMember(destProperty);
4948
var sourceProperty = typeMap.SourceType.GetInheritedMember(destProperty.Name);
@@ -57,20 +56,7 @@ public void Configure(TypeMap typeMap)
5756
IgnoreDestinationMember(destProperty);
5857
}
5958
}
60-
61-
var destTypeInfo = typeMap.DestinationTypeDetails;
62-
if(!typeMap.DestinationType.IsAbstract)
63-
{
64-
foreach(var destCtor in destTypeInfo.Constructors.OrderByDescending(ci => ci.GetParameters().Length))
65-
{
66-
if(typeMap.Profile.MapDestinationCtorToSource(typeMap, destCtor, typeMap.SourceTypeDetails, CtorParamConfigurations))
67-
{
68-
break;
69-
}
70-
}
71-
}
72-
73-
59+
MapDestinationCtorToSource(typeMap, CtorParamConfigurations);
7460
foreach (var action in TypeMapActions)
7561
{
7662
action(typeMap);
@@ -113,6 +99,49 @@ public void Configure(TypeMap typeMap)
11399
}
114100
}
115101

102+
private void MapDestinationCtorToSource(TypeMap typeMap, List<ICtorParameterConfiguration> ctorParamConfigurations)
103+
{
104+
var ctorMap = typeMap.ConstructorMap;
105+
if (ctorMap != null)
106+
{
107+
foreach (var paramMap in ctorMap.CtorParams)
108+
{
109+
paramMap.CanResolveValue = paramMap.CanResolveValue || IsConfigured(paramMap.Parameter);
110+
}
111+
return;
112+
}
113+
if (typeMap.DestinationType.IsAbstract || !typeMap.Profile.ConstructorMappingEnabled)
114+
{
115+
return;
116+
}
117+
foreach (var destCtor in typeMap.DestinationTypeDetails.Constructors.OrderByDescending(ci => ci.GetParameters().Length))
118+
{
119+
var ctorParameters = destCtor.GetParameters();
120+
if (ctorParameters.Length == 0)
121+
{
122+
break;
123+
}
124+
ctorMap = new ConstructorMap(destCtor, typeMap);
125+
foreach (var parameter in ctorParameters)
126+
{
127+
var resolvers = new LinkedList<MemberInfo>();
128+
var canResolve = typeMap.Profile.MapDestinationPropertyToSource(typeMap.SourceTypeDetails, destCtor.DeclaringType, parameter.GetType(), parameter.Name, resolvers);
129+
if ((!canResolve && parameter.IsOptional) || IsConfigured(parameter))
130+
{
131+
canResolve = true;
132+
}
133+
ctorMap.AddParameter(parameter, resolvers.ToArray(), canResolve);
134+
}
135+
typeMap.ConstructorMap = ctorMap;
136+
if (ctorMap.CanResolve)
137+
{
138+
break;
139+
}
140+
}
141+
return;
142+
bool IsConfigured(ParameterInfo parameter) => ctorParamConfigurations.Any(c => c.CtorParamName == parameter.Name);
143+
}
144+
116145
protected IEnumerable<IPropertyMapConfiguration> MapToSourceMembers() =>
117146
MemberConfigurations.Where(m => m.SourceExpression != null && m.SourceExpression.Body == m.SourceExpression.Parameters[0]);
118147

src/AutoMapper/ProfileMap.cs

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -230,42 +230,15 @@ private void ApplyDerivedMaps(TypeMap baseMap, TypeMap typeMap, IConfigurationPr
230230
ApplyDerivedMaps(baseMap, derivedMap, configurationProvider);
231231
}
232232
}
233-
234-
public bool MapDestinationCtorToSource(TypeMap typeMap, ConstructorInfo destCtor, TypeDetails sourceTypeInfo, List<ICtorParameterConfiguration> ctorParamConfigurations)
235-
{
236-
var ctorParameters = destCtor.GetParameters();
237-
238-
if (ctorParameters.Length == 0 || !ConstructorMappingEnabled)
239-
return false;
240-
241-
var ctorMap = new ConstructorMap(destCtor, typeMap);
242-
243-
foreach (var parameter in ctorParameters)
244-
{
245-
var resolvers = new LinkedList<MemberInfo>();
246-
247-
var canResolve = MapDestinationPropertyToSource(sourceTypeInfo, destCtor.DeclaringType, parameter.GetType(), parameter.Name, resolvers);
248-
if ((!canResolve && parameter.IsOptional) || ctorParamConfigurations.Any(c => c.CtorParamName == parameter.Name))
249-
{
250-
canResolve = true;
251-
}
252-
ctorMap.AddParameter(parameter, resolvers.ToArray(), canResolve);
253-
}
254-
255-
typeMap.ConstructorMap = ctorMap;
256-
257-
return ctorMap.CanResolve;
258-
}
259233

260234
public bool MapDestinationPropertyToSource(TypeDetails sourceTypeInfo, Type destType, Type destMemberType, string destMemberInfo, LinkedList<MemberInfo> members)
261235
{
262236
if (string.IsNullOrEmpty(destMemberInfo))
263237
{
264238
return false;
265239
}
266-
return MemberConfigurations.Any(_ => _.MapDestinationPropertyToSource(this, sourceTypeInfo, destType, destMemberType, destMemberInfo, members));
240+
return MemberConfigurations.Any(memberConfig => memberConfig.MapDestinationPropertyToSource(this, sourceTypeInfo, destType, destMemberType, destMemberInfo, members));
267241
}
268-
269242
}
270243

271244
public readonly struct IncludedMember

src/UnitTests/ForAllMaps.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,32 @@ public void Should_configure_all_maps()
6868
_destination2.Number.ShouldBe(-1);
6969
}
7070
}
71+
public class ForAllMapsWithConstructors : AutoMapperSpecBase
72+
{
73+
class Source
74+
{
75+
}
76+
class Destination
77+
{
78+
public Destination(int first, int second)
79+
{
80+
First = first;
81+
Second = second;
82+
}
83+
public int First { get; }
84+
public int Second { get; }
85+
}
86+
protected override MapperConfiguration Configuration => new MapperConfiguration(cfg=>
87+
{
88+
cfg.ForAllMaps((_, c) => c.ForCtorParam("second", o => o.MapFrom(s => 2)));
89+
cfg.CreateMap<Source, Destination>().ForCtorParam("first", o => o.MapFrom(s => 1));
90+
});
91+
[Fact]
92+
public void Should_map_ok()
93+
{
94+
var result = Map<Destination>(new Source());
95+
result.First.ShouldBe(1);
96+
result.Second.ShouldBe(2);
97+
}
98+
}
7199
}

0 commit comments

Comments
 (0)