AutoMapper如何将对象A映射到对象B,这取决于上下文

召唤所有AutoMapper大师!

我希望能够根据运行时的上下文以不同方式将对象A映射到对象B. 特别是,我想在一个映射的情况下忽略某些属性,并在另一个案例中映射所有属性。

我所经历的是Mapper.CreateMap可以在不同的映射情况下成功调用,但是,一旦调用了CreateMap,就会设置特定的一对类型的映射,并且随后的CreateMap调用不会改变它,这可能会描述映射不同。

我找到了一篇博文,主张Mapper.Reset()来解决这个问题,然而,Mapper类的静态特性意味着碰撞和崩溃发生只是时间问题。

有没有办法做到这一点?

我认为我需要的是每个appdomain调用Mapper.CreateMap一次,然后,能够调用Mapper.Map,提示应该包含/排除哪些属性。

现在,我正在考虑通过编写一个包含映射配置实例的非静态映射类来更改源代码。 性能不佳,但线程安全。

我有什么选择。 可以做些什么? Automapper似乎很有前途。

Mapper类只是Configuration和MappingEngine对象之上的一个瘦包装器。 您可以创建Configuration / MappingEngine对象的单独实例(仍然使用单例),并根据需要使用您选择的IoC容器加载正确的容器。

最好的选择仍然是使用不同的目标类型。 关于真正支持此function的真正困难的部分是类型映射的固有层次性。 顶级对象可能具有映射配置文件,而较低级别的对象可能没有。 介于两者之间可能有或没有等等。

只是为了补充Jimmy的答案,这里是在没有静态Mapper的情况下使用AutoMapper所需的代码

从版本4.2.1开始, Automapper有一个受制裁的非静态映射器和配置(感谢Jimmy!)。

var config = new MapperConfiguration(cfg => { cfg.CreateMap(); }); var mapper = config.CreateMapper(); 

新版本中还有许多其他有用的选项(如配置文件),用于创建不同的映射器实例。 您可以在官方文档中获取所有详细信息

(对于4.1.1版本更正)

 // Configuration AutoMapper.Mappers.MapperRegistry.Reset(); var autoMapperCfg = new AutoMapper.ConfigurationStore(new TypeMapFactory(), AutoMapper.Mappers.MapperRegistry.Mappers); var mappingEngine = new AutoMapper.MappingEngine(autoMapperCfg); autoMapperCfg.Seal(); //Usage example autoMapperCfg.CreateMap(); var b = mappingEngine.Map(a); 

(对于版本3.2.1更正)

 // Configuration var platformSpecificRegistry = AutoMapper.Internal.PlatformAdapter.Resolve(); platformSpecificRegistry.Initialize(); var autoMapperCfg = new AutoMapper.ConfigurationStore(new TypeMapFactory(), AutoMapper.Mappers.MapperRegistry.Mappers); var mappingEngine = new AutoMapper.MappingEngine(autoMapperCfg); //Usage example autoMapperCfg.CreateMap(); var b = mappingEngine.Map(a); 

(对于2.2.1版本更正)

 // Configuration var autoMapperCfg = new AutoMapper.ConfigurationStore(new AutoMapper.TypeMapFactory(), AutoMapper.Mappers.MapperRegistry.AllMappers()); var mappingEngine = new AutoMapper.MappingEngine(autoMapperCfg); //Usage example autoMapperCfg.CreateMap(); var b = mappingEngine.Map(a); 

对我来说,听起来更好的设计可能是拥有多个目标类(可能inheritance自公共基础或实现通用接口)

如果未在其中一个变体中使用未映射的属性,则可以将它们完全保留(使编译时保证不会错误地使用它们),在访问时抛出exception(不如编译时间)保证,但有时您需要实现完整的接口)或甚至使用替代值。

例如:

 public class Source { public string Name {get;set;} public BigEntity {get;set;} /* other members */ } public class SourceDTO { public string Name {get;set;} public BigEntity {get;set;} } public class SourceSummaryDTO { public string Name {get;set;} } 

或者,你可以这样做:

 public class SourceSummaryDTO : SourceDTO { public string Name {get;set;} public BigEntity { get{throw new NotSupportedException();} set{throw new NotSupportedException();} } } 

这样,您可以传递SourceSummaryDTO,就像它是SourceDTO一样。

拥有有条件填充的属性听起来像是给我带来麻烦的一个秘诀 – 我宁愿让类明确包含它们包含的内容,尤其是数据传输对象。

对我来说,Automapper的最大优点是能够validation映射,然后知道目标类的每个属性都将被填充。