代码之家  ›  专栏  ›  技术社区  ›  Alex KeySmith

使用嵌套构造函数时的AssertConfigurationIsValid(),而不忽略私有setter

  •  0
  • Alex KeySmith  · 技术社区  · 5 年前

    使用以下示例(LinqPad):

    void Main()
    {
    
        var config = new MapperConfiguration(cfg =>
        {
            cfg.CreateMap<Source, DestinationNested>()
                .ConstructUsing((source, context) => new DestinationNested(source.InnerValue));
    
            cfg.CreateMap<Source, DestinationOuter>()
                .ForMember(x => x.OuterValue, y => y.MapFrom(z => z.OuterValue))
                .ConstructUsing((source, context) =>
                {
                    return new DestinationOuter(source.OuterValue, context.Mapper.Map<DestinationNested>(source));
                });
    
        });
    
        var src = new Source { OuterValue = 999, InnerValue = 111 };
    
        var mapper = config.CreateMapper();
        var mapped = mapper.Map<DestinationOuter>(src);
    
        mapped.Dump();
    
        mapper.ConfigurationProvider.AssertConfigurationIsValid();
    }
    
    public class Source
    {
        public int OuterValue { get; set; }
        public int InnerValue { get; set; }
    }
    
    public class DestinationOuter
    {
        public int OuterValue { get; private set; }
        public DestinationNested destinationNested { get; private set; }
    
        public DestinationOuter(int outerValue, DestinationNested destinationNested)
        {
            this.OuterValue = outerValue;
            this.destinationNested = destinationNested;
        }
    }
    
    public class DestinationNested
    {
        public int NestedValue { get; private set; }
    
        public DestinationNested(int nestedValue)
        {
            this.NestedValue = nestedValue;
        }
    }
    

    AssertConfigurationIsValid()当前在使用constructusing时引发有关属性的异常。

    实际上,它确实映射正确,但我希望AssertConfigurationIsValid作为测试套件的一部分来查找回归(无需对映射器进行手动测试)。

    我想保证我的所有属性都从源映射到目标 通过 建设者。我希望使用一个Contractor,因为它是我的域层,并且Contractor强制执行强制项。

    我不想通过ignoreallproperties和accessiblesetter()功能忽略所有私有setter,因为我可能会忽略一些实际上没有设置的东西。

    理想情况下,我也不想对构造函数中出现的每个属性执行手动Ignore(),因为这样会留下代码漂移的间隙。

    我在Automapper中尝试过各种组合,但到目前为止还没有成功。

    我想这是一个静态分析挑战;我想知道我的构造器覆盖了目的地的所有属性。我想知道,这场争论是从源头上通过的。

    我意识到Automapper在这一点上并不是很自动,有没有一个很好的方法来依靠Automapper进行测试,或者这是一个静态分析问题?

    0 回复  |  直到 5 年前
        1
  •  1
  •   Lucian Bargaoanu    5 年前

    这是我要的。

    static void Main(string[] args)
    {
        try{
        var mapperCfg = new AutoMapper.MapperConfiguration(cfg =>
        {
            cfg.CreateMap<Source, DestinationOuter>().ForCtorParam("destinationNested", o => o.MapFrom(s => new DestinationNested(s.InnerValue)));
        });
        mapperCfg.AssertConfigurationIsValid();
        var mapper = mapperCfg.CreateMapper();
    
        var src = new Source { OuterValue = 999, InnerValue = 111 };
        mapper.Map<DestinationOuter>(src).Dump();
        }catch(Exception ex){
            ex.ToString().Dump();
        }
    }
    public class Source
    {
        public int OuterValue { get; set; }
        public int InnerValue { get; set; }
    }
    public class DestinationOuter
    {
        public int OuterValue { get; }
        public DestinationNested DestinationNested { get; }
    
        public DestinationOuter(int outerValue, DestinationNested destinationNested)
        {
            this.OuterValue = outerValue;
            this.DestinationNested = destinationNested;
        }
    }
    public class DestinationNested
    {
        public int NestedValue { get; private set; }
    
        public DestinationNested(int nestedValue)
        {
            this.NestedValue = nestedValue;
        }
    }
    
        2
  •  0
  •   Alex KeySmith    5 年前

    在阅读了大量文档、使用调试器逐步完成集成测试和几天的良好实验之后,这是我所拥有的最好的:

    var config = new MapperConfiguration(cfg =>
        {
            cfg.CreateMap<Source, DestinationNested>()
                .ForCtorParam("nestedValue", x => x.MapFrom(y => y.InnerValue))
                .ForMember(x => x.NestedValue, x => x.MapFrom(y => y.InnerValue));
    
            cfg.CreateMap<Source, DestinationOuter>()
                .ForPath(x => x.destinationNested.NestedValue, x => x.MapFrom(y => y.InnerValue))
                .ForCtorParam("destinationNested", x => x.MapFrom(y => y));
        });
    

    我对此非常满意;它消除了在我更广泛的代码库中构造嵌套对象的constructusing()味道。如果我的目标对象没有填充,它会警告我。理想情况下,构造函数参数字符串应该是类型安全的,但我理解为什么它不能(也许这是一个有趣的Roslyn代码分析器项目的另一天:-)

    秘密的调味品(媒体的热)是 x => x.MapFrom(y => y) 再加上 .ForPath(x => x.destinationNested.NestedValue, x => x.MapFrom(y => y.InnerValue)) 它似乎向AutoMapper提供了足够的提示,表明destinationNested与InnerValue相关,并且constructor param被重命名为“destinationNested”。神奇之处在于它没有使用上下文来构造嵌套对象 x.MapFrom(y => y) 似乎让它使用属性映射来代替*。

    *这是我的外行的解释,我还没有遵循足够的AutoMapper源代码来真正理解属性映射和构造函数映射之间的关系。通过阅读一些GitHub票据,我认为它们是不同的概念。

    我也没见过 x.MapFrom(y=>y) 在文档中提到,所以我有兴趣进一步了解它。