使用嵌套 ConstructUsing 时的 AssertConfigurationIsValid(),不忽略私有设置器
AssertConfigurationIsValid() when using nested ConstructUsing, without ignoring private setters
用下面的例子(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() 目前在我使用 ContructUsing 时抛出有关属性的异常。
实际上它确实映射正确,但我希望 AssertConfigurationIsValid 作为我的测试套件的一部分来寻找回归(无需对映射器进行手动测试)。
我想确保我的所有属性都从源映射到目标通过构造函数。我希望使用构造函数,因为它是我的域层,并且构造函数强制执行强制性项目。
我不想通过 IgnoreAllPropertiesWithAnInaccessibleSetter() 功能忽略所有私有设置器,因为我可能会忽略一些我实际上没有设置的东西。
理想情况下,我也不想对构造函数中出现的每个属性执行手动 Ignore(),因为这会留下代码漂移的空隙。
我在 Automapper 中尝试了各种组合,但到目前为止没有成功。
我想这是一个静态分析挑战;我想知道我的构造函数涵盖了目标中的所有属性。我想知道构造函数正在传递来自源的所有内容。
我意识到 Automapper 在这一点上并不是很自动化,是否有一种很好的方法可以依靠 automapper 进行此测试,或者这是一个静态分析问题?
在阅读了大量文档、使用调试器逐步完成集成测试以及几天的良好实验之后,这是我拥有的最好的:
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));
});
我很满意;它摆脱了在我更广泛的代码库中构建嵌套对象的 ContructUsing() 气味。如果我的目标对象未填充,它会警告我。理想情况下,构造函数参数字符串应该是类型安全的,但我理解为什么它不能(也许这是另一天有趣的 Roslyn 代码分析器项目的东西:-))
秘诀(新闻热点)是 x => x.MapFrom(y => y)
加上 .ForPath(x => x.destinationNested.NestedValue, x => x.MapFrom(y => y.InnerValue))
它似乎给了 AutoMapper 足够的提示,即 destinationNested 与 InnerValue 相关,并且构造函数参数已重命名至 "destinationNested"。神奇之处在于,看起来无辜的 x.MapFrom(y => y)
没有使用上下文来构造嵌套对象,而是让它使用 属性 映射代替*。
*这是我的外行人的解释,我还没有遵循足够多的 AutoMapper 源代码来真正理解 属性 映射和构造函数映射之间的关系。阅读了一些 GitHub 票,我认为它们是不同的概念。
我也没有在文档中看到 x.MapFrom(y => y)
,所以我有兴趣了解更多相关信息。
这是我的看法。
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;
}
}
用下面的例子(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() 目前在我使用 ContructUsing 时抛出有关属性的异常。
实际上它确实映射正确,但我希望 AssertConfigurationIsValid 作为我的测试套件的一部分来寻找回归(无需对映射器进行手动测试)。
我想确保我的所有属性都从源映射到目标通过构造函数。我希望使用构造函数,因为它是我的域层,并且构造函数强制执行强制性项目。
我不想通过 IgnoreAllPropertiesWithAnInaccessibleSetter() 功能忽略所有私有设置器,因为我可能会忽略一些我实际上没有设置的东西。
理想情况下,我也不想对构造函数中出现的每个属性执行手动 Ignore(),因为这会留下代码漂移的空隙。
我在 Automapper 中尝试了各种组合,但到目前为止没有成功。
我想这是一个静态分析挑战;我想知道我的构造函数涵盖了目标中的所有属性。我想知道构造函数正在传递来自源的所有内容。
我意识到 Automapper 在这一点上并不是很自动化,是否有一种很好的方法可以依靠 automapper 进行此测试,或者这是一个静态分析问题?
在阅读了大量文档、使用调试器逐步完成集成测试以及几天的良好实验之后,这是我拥有的最好的:
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));
});
我很满意;它摆脱了在我更广泛的代码库中构建嵌套对象的 ContructUsing() 气味。如果我的目标对象未填充,它会警告我。理想情况下,构造函数参数字符串应该是类型安全的,但我理解为什么它不能(也许这是另一天有趣的 Roslyn 代码分析器项目的东西:-))
秘诀(新闻热点)是 x => x.MapFrom(y => y)
加上 .ForPath(x => x.destinationNested.NestedValue, x => x.MapFrom(y => y.InnerValue))
它似乎给了 AutoMapper 足够的提示,即 destinationNested 与 InnerValue 相关,并且构造函数参数已重命名至 "destinationNested"。神奇之处在于,看起来无辜的 x.MapFrom(y => y)
没有使用上下文来构造嵌套对象,而是让它使用 属性 映射代替*。
*这是我的外行人的解释,我还没有遵循足够多的 AutoMapper 源代码来真正理解 属性 映射和构造函数映射之间的关系。阅读了一些 GitHub 票,我认为它们是不同的概念。
我也没有在文档中看到 x.MapFrom(y => y)
,所以我有兴趣了解更多相关信息。
这是我的看法。
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;
}
}