为什么AutoMapper在属性是接口类型时尝试映射null属性?

问题描述:

在AutoMapper 5.0.2下:为什么AutoMapper在属性是接口类型时尝试映射null属性?

当源对象具有接口类型属性时,即使属性为null,为该接口类型定义的映射也将被完全评估。如果映射使用ResolveUsing,这是有问题的,因为它可能不会期望null并可能抛出。

下面的测试夹具使用相当人为的映射来强调该问题。一个测试通过,则其他失败:

[TestFixture] 
public class NullPropertyTests 
{ 
    public class ChildClass : IChildInterface 
    { 
     public string OtherValue { get; set; } 
     public string Value { get; set; } 
    } 

    public interface IChildInterface 
    { 
     string Value { get; set; } 
    } 

    public class ClassReferencesChildClass 
    { 
     public ChildClass Child { get; set; } 
    } 

    public class ClassReferencesChildInterface 
    { 
     public IChildInterface Child { get; set; } 
    } 

    public class DtoClass 
    { 
     public DtoChildClass Child { get; set; } 
    } 

    public class DtoChildClass 
    { 
     public string OtherValue { get; set; } 
     public string Value { get; set; } 
    } 

    [Test] 
    public void BreakingTest() 
    { 
     var mapper = CreateAndValidateMapper(e => 
     { 
      e.CreateMap<ClassReferencesChildInterface, DtoClass>(); 

      e.CreateMap<IChildInterface, DtoChildClass>() 
       .Include<ChildClass, DtoChildClass>() 
       .ForMember(d => d.Value, x => x.ResolveUsing(c => DoStuff(c.Value?.Split(' ')))) 
       .ForMember(d => d.OtherValue, x => x.Ignore()); 
      e.CreateMap<ChildClass, DtoChildClass>(); 
     }); 

     // This fails due to a NullReferenceException: 
     mapper.Map<DtoClass>(new ClassReferencesChildInterface { Child = null }); 
    } 

    [Test] 
    public void PassingTest() 
    { 
     var mapper = CreateAndValidateMapper(e => 
     { 
      e.CreateMap<ClassReferencesChildClass, DtoClass>(); 

      e.CreateMap<IChildInterface, DtoChildClass>() 
       .Include<ChildClass, DtoChildClass>() 
       .ForMember(d => d.Value, x => x.ResolveUsing(c => DoStuff(c.Value?.Split(' ')))) 
       .ForMember(d => d.OtherValue, x => x.Ignore()); 
      e.CreateMap<ChildClass, DtoChildClass>(); 
     }); 

     mapper.Map<DtoClass>(new ClassReferencesChildClass { Child = null }); 
    } 

    private static string DoStuff(string[] value) 
    { 
     return value.FirstOrDefault(); 
    } 

    private static IMapper CreateAndValidateMapper(Action<IMapperConfigurationExpression> configure) 
    { 
     var configuration = new MapperConfiguration(configure); 
     configuration.AssertConfigurationIsValid(); 
     return configuration.CreateMapper(); 
    } 
} 

在AutoMapper 3.2.1(与类型等根据需要调整为编译)两个测试将通过。

我们可以修改几十个映射来明确容忍空值,但对于以前工作得很好的东西来说,似乎过于冗长。

这是预期的行为?有没有一种解决方法,它不需要重复大量的映射?

我提出了这个issue with the Automapper project。它似乎是固定的,修复程序将在5.1.0版本中发布。