Skip to content

Commit bb1c612

Browse files
authored
Merge pull request #3336 from timmi-on-rails/issue-3329
Reverse the string based MapFrom
2 parents c755b9d + 40e8fd8 commit bb1c612

File tree

3 files changed

+80
-10
lines changed

3 files changed

+80
-10
lines changed

src/AutoMapper/Configuration/MappingExpression.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,7 @@ public IMappingExpression ReverseMap()
1818
{
1919
var reversedTypes = new TypePair(Types.DestinationType, Types.SourceType);
2020
var reverseMap = new MappingExpression(reversedTypes, MemberList.None);
21-
if(!reversedTypes.IsGenericTypeDefinition)
22-
{
23-
reverseMap.MemberConfigurations.AddRange(MemberConfigurations.Select(m => m.Reverse()).Where(m => m != null));
24-
}
21+
reverseMap.MemberConfigurations.AddRange(MemberConfigurations.Select(m => m.Reverse()).Where(m => m != null));
2522
ReverseMapExpression = reverseMap;
2623
reverseMap.IncludeMembers(MapToSourceMembers().Select(m => m.DestinationMember.Name).ToArray());
2724
foreach(var includedMemberName in IncludedMembersNames)

src/AutoMapper/Configuration/MemberConfigurationExpression.cs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ namespace AutoMapper.Configuration
1010

1111
public class MemberConfigurationExpression<TSource, TDestination, TMember> : IMemberConfigurationExpression<TSource, TDestination, TMember>, IPropertyMapConfiguration
1212
{
13-
private LambdaExpression _sourceMember;
13+
private LambdaExpression _sourceExpression;
14+
private MemberInfo _sourceMember;
1415
private readonly Type _sourceType;
1516
protected List<Action<PropertyMap>> PropertyMapActions { get; } = new List<Action<PropertyMap>>();
1617

@@ -116,13 +117,13 @@ public void MapFrom<TSourceMember>(Expression<Func<TSource, TSourceMember>> mapE
116117

117118
internal void MapFromUntyped(LambdaExpression sourceExpression)
118119
{
119-
_sourceMember = sourceExpression;
120+
_sourceExpression = sourceExpression;
120121
PropertyMapActions.Add(pm => pm.MapFrom(sourceExpression));
121122
}
122123

123124
public void MapFrom(string sourceMemberName)
124125
{
125-
_sourceType.GetFieldOrProperty(sourceMemberName);
126+
_sourceMember = _sourceType.GetFieldOrProperty(sourceMemberName);
126127
PropertyMapActions.Add(pm => pm.MapFrom(sourceMemberName));
127128
}
128129

@@ -337,11 +338,24 @@ private void Apply(PropertyMap propertyMap)
337338
propertyMap.CheckMappedReadonly();
338339
}
339340

340-
public LambdaExpression SourceExpression => _sourceMember;
341+
public LambdaExpression SourceExpression => _sourceExpression;
341342
public LambdaExpression GetDestinationExpression() => MemberAccessLambda(DestinationMember);
342343

343-
public IPropertyMapConfiguration Reverse() =>
344-
PathConfigurationExpression<TDestination, TSource, object>.Create(_sourceMember, GetDestinationExpression());
344+
public IPropertyMapConfiguration Reverse()
345+
{
346+
var destinationType = DestinationMember.DeclaringType;
347+
if (_sourceMember != null)
348+
{
349+
var reversedMemberConfiguration = new MemberConfigurationExpression<TDestination, TSource, object>(_sourceMember, destinationType);
350+
reversedMemberConfiguration.MapFrom(DestinationMember.Name);
351+
return reversedMemberConfiguration;
352+
}
353+
if (destinationType.IsGenericTypeDefinition) // .ForMember("InnerSource", o => o.MapFrom(s => s))
354+
{
355+
return null;
356+
}
357+
return PathConfigurationExpression<TDestination, TSource, object>.Create(_sourceExpression, GetDestinationExpression());
358+
}
345359

346360
public void DontUseDestinationValue() => SetUseDestinationValue(false);
347361
}

src/UnitTests/ReverseMapping.cs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,34 @@ public void Should_unflatten()
202202
}
203203
}
204204

205+
public class ReverseMapFromSourceMemberName : AutoMapperSpecBase
206+
{
207+
public class Source
208+
{
209+
public int Value { get; set; }
210+
}
211+
212+
public class Destination
213+
{
214+
public int Value2 { get; set; }
215+
}
216+
217+
protected override MapperConfiguration Configuration => new MapperConfiguration(cfg =>
218+
{
219+
cfg.CreateMap<Source, Destination>()
220+
.ForMember(d => d.Value2, o => o.MapFrom("Value"))
221+
.ReverseMap();
222+
});
223+
224+
[Fact]
225+
public void Should_reverse_map_ok()
226+
{
227+
Destination destination = new Destination { Value2 = 1337 };
228+
Source source = Mapper.Map<Source>(destination);
229+
source.Value.ShouldBe(1337);
230+
}
231+
}
232+
205233
public class ReverseDefaultFlatteningWithIgnoreMember : AutoMapperSpecBase
206234
{
207235
public class Order
@@ -594,4 +622,35 @@ public void Should_create_a_map_with_the_reverse_items()
594622
_source.Value.ShouldBe(10);
595623
}
596624
}
625+
626+
public class When_reverse_mapping_open_generics_with_MapFrom : AutoMapperSpecBase
627+
{
628+
public class Source<T>
629+
{
630+
public T Value { get; set; }
631+
public string StringValue { get; set; }
632+
}
633+
public class Destination<T>
634+
{
635+
public T Value2 { get; set; }
636+
public string StringValue2 { get; set; }
637+
}
638+
639+
protected override MapperConfiguration Configuration { get; } = new MapperConfiguration(cfg =>
640+
{
641+
cfg.CreateMap(typeof(Source<>), typeof(Destination<>))
642+
.ForMember("Value2", o => o.MapFrom("Value"))
643+
.ForMember("StringValue2", o => o.MapFrom("StringValue"))
644+
.ReverseMap();
645+
});
646+
647+
[Fact]
648+
public void Should_reverse_map_ok()
649+
{
650+
Destination<int> destination = new Destination<int> { Value2 = 1337, StringValue2 = "StringValue2" };
651+
Source<int> source = Mapper.Map<Destination<int>, Source<int>>(destination);
652+
source.Value.ShouldBe(1337);
653+
source.StringValue.ShouldBe("StringValue2");
654+
}
655+
}
597656
}

0 commit comments

Comments
 (0)