Skip to content

Commit cade5e6

Browse files
committed
Continue chaining after AsProxy
1 parent 9ccbd7c commit cade5e6

File tree

3 files changed

+117
-6
lines changed

3 files changed

+117
-6
lines changed

src/AutoMapper/Configuration/IMappingExpressionBase.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,8 @@ public interface IMappingExpressionBase<TSource, TDestination, out TMappingExpre
168168
/// <summary>
169169
/// Create at runtime a proxy type implementing the destination interface.
170170
/// </summary>
171-
void AsProxy();
171+
/// <returns>Itself</returns>
172+
TMappingExpression AsProxy();
172173
/// <summary>
173174
/// Skip normal member mapping and convert using a <see cref="ITypeConverter{TSource,TDestination}"/> instantiated during mapping
174175
/// Use this method if you need to specify the converter type at runtime

src/AutoMapper/Configuration/MappingExpressionBase.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -520,13 +520,14 @@ public TMappingExpression IgnoreAllSourcePropertiesWithAnInaccessibleSetter()
520520
public void ConvertUsing(Expression<Func<TSource, TDestination>> mappingFunction) =>
521521
TypeMapActions.Add(tm => tm.CustomMapExpression = mappingFunction);
522522

523-
public void AsProxy()
523+
public TMappingExpression AsProxy()
524524
{
525525
if (!DestinationType.IsInterface)
526526
{
527527
throw new InvalidOperationException("Only interfaces can be proxied. " + DestinationType);
528528
}
529529
TypeMapActions.Add(tm => tm.AsProxy = true);
530+
return this as TMappingExpression;
530531
}
531532
}
532533
}

src/UnitTests/InterfaceMapping.cs

Lines changed: 113 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -309,18 +309,27 @@ public class When_mapping_a_concrete_type_to_an_interface_type : AutoMapperSpecB
309309
public class Source
310310
{
311311
public int Value { get; set; }
312+
public int Value1 { get; set; }
312313
}
313314

314315
public interface IDestination
315316
{
316317
int Value { get; set; }
318+
int Value2 { get; set; }
319+
string Value3 { get; set; }
317320
}
318321

319-
protected override MapperConfiguration CreateConfiguration() => new(cfg =>cfg.CreateMap<Source, IDestination>().AsProxy());
322+
protected override MapperConfiguration CreateConfiguration() => new(cfg =>cfg.CreateMap<Source, IDestination>().AsProxy()
323+
.ForMember(x => x.Value2, o => o.MapFrom(x => x.Value1))
324+
.ForMember(x => x.Value3, o => o.Ignore())
325+
.AfterMap((_, d) =>
326+
{
327+
d.Value3 = "value 3";
328+
}));
320329

321330
protected override void Because_of()
322331
{
323-
_result = Mapper.Map<Source, IDestination>(new Source {Value = 5});
332+
_result = Mapper.Map<Source, IDestination>(new Source {Value = 5, Value1 = 50});
324333
}
325334

326335
[Fact]
@@ -329,10 +338,110 @@ public void Should_create_an_implementation_of_the_interface()
329338
_result.Value.ShouldBe(5);
330339
}
331340

341+
[Fact]
342+
public void Should_apply_rules_after_proxying()
343+
{
344+
_result.Value2.ShouldBe(50);
345+
_result.Value3.ShouldBe("value 3");
346+
}
347+
332348
[Fact]
333349
public void Should_not_derive_from_INotifyPropertyChanged()
334350
{
335-
_result.ShouldNotBeOfType<INotifyPropertyChanged>();
351+
_result.ShouldNotBeOfType<INotifyPropertyChanged>();
352+
}
353+
}
354+
355+
public class When_mapping_an_interface_type_to_a_concrete_type_and_reverse : AutoMapperSpecBase
356+
{
357+
public interface ISource
358+
{
359+
int Value { get; set; }
360+
}
361+
362+
public class Destination
363+
{
364+
public int Value { get; set; }
365+
}
366+
367+
protected override MapperConfiguration CreateConfiguration() => new(cfg =>
368+
cfg.CreateMap<ISource, Destination>().ReverseMap());
369+
370+
[Fact]
371+
public void Should_not_convert_to_interface()
372+
{
373+
Should.Throw<AutoMapperMappingException>(() => Mapper.Map<Destination, ISource>(new Destination {Value = 5}))
374+
.Message.ShouldStartWith("Cannot create interface " + typeof(ISource).FullName);
375+
}
376+
}
377+
378+
public class When_mapping_an_interface_type_to_an_interface_type_and_reverse : AutoMapperSpecBase
379+
{
380+
public interface ISource
381+
{
382+
int Value { get; set; }
383+
}
384+
385+
public class Source: ISource
386+
{
387+
public int Value { get; set; }
388+
}
389+
390+
public interface IDestination
391+
{
392+
int Value { get; set; }
393+
}
394+
395+
protected override MapperConfiguration CreateConfiguration() => new(cfg =>
396+
cfg.CreateMap<ISource, IDestination>().AsProxy().ReverseMap().AsProxy());
397+
398+
[Fact]
399+
public void Should_create_an_implementation_of_the_destination_interface()
400+
{
401+
var destination = Mapper.Map<ISource, IDestination>(new Source {Value = 5});
402+
destination.Value.ShouldBe(5);
403+
}
404+
405+
[Fact]
406+
public void Should_map_implementation_of_the_interface_to_the_proxied_implementation()
407+
{
408+
var destination = Mapper.Map<ISource, IDestination>(new Source {Value = 5});
409+
var reversed = Mapper.Map<IDestination, ISource>(destination);
410+
411+
reversed.ShouldNotBeOfType<Source>();
412+
reversed.Value.ShouldBe(5);
413+
}
414+
}
415+
416+
public class When_mapping_a_concrete_type_to_an_interface_type_and_reverse : AutoMapperSpecBase
417+
{
418+
public class Source
419+
{
420+
public int Value { get; set; }
421+
}
422+
423+
public interface IDestination
424+
{
425+
int Value { get; set; }
426+
}
427+
428+
protected override MapperConfiguration CreateConfiguration() => new(cfg =>
429+
cfg.CreateMap<Source, IDestination>().AsProxy().ReverseMap());
430+
431+
[Fact]
432+
public void Should_create_an_implementation_of_the_destination_interface()
433+
{
434+
var destination = Mapper.Map<Source, IDestination>(new Source {Value = 5});
435+
destination.Value.ShouldBe(5);
436+
}
437+
438+
[Fact]
439+
public void Should_map_implementation_of_the_interface_to_the_class()
440+
{
441+
var destination = Mapper.Map<Source, IDestination>(new Source {Value = 5});
442+
var reversed = Mapper.Map<IDestination, Source>(destination);
443+
444+
reversed.Value.ShouldBe(5);
336445
}
337446
}
338447

@@ -378,7 +487,7 @@ public void Should_notify_property_changes()
378487
var count = 0;
379488
_result.PropertyChanged += (o, e) => {
380489
count++;
381-
o.ShouldBeSameAs(_result);
490+
o.ShouldBeSameAs(_result);
382491
e.PropertyName.ShouldBe("Value");
383492
};
384493

0 commit comments

Comments
 (0)