当前栏目
聊一下对象到对象映射之AutoMapper
本文转载自微信公众号「UP技术控」,作者conan5566。转载本文请联系UP技术控公众号。
概述
AutoMapper 是一个对象-对象映射器,可以将一个对象映射到另一个对象。
用来解决一个看似复杂的问题,这种类型的代码编写起来相当枯燥乏味,
官网地址:http://automapper.org/
官方文档:https://docs.automapper.org/en/latest/
入门
AutoMapper支持使用静态服务位置构造“自定义值解析器”,“自定义类型转换器”和“值转换器”的功能:
- var configuration = new MapperConfiguration(cfg =>
- {
- cfg.ConstructServicesUsing(ObjectFactory.GetInstance);
- cfg.CreateMap<Source, Destination>();
- });
或动态服务位置,用于基于实例的容器(包括子容器/嵌套容器):
- var mapper = new Mapper(configuration, childContainer.GetInstance);
- var dest = mapper.Map(new Source { Value = 15 });
您可以使用配置文件定义配置。然后,通过在启动时调用IServiceCollection扩展方法AddAutoMapper,使AutoMapper知道这些概要文件在哪些程序集中定义:
- services.AddAutoMapper(profileAssembly1, profileAssembly2 /*, ...*/);
或标记类型:
- services.AddAutoMapper(typeof(ProfileTypeFromAssembly1), typeof(ProfileTypeFromAssembly2) /*, ...*/);
现在,您可以在运行时将AutoMapper注入服务/控制器中:
- public class EmployeesController {
- private readonly IMapper _mapper;
- public EmployeesController(IMapper mapper) => _mapper = mapper;
- // use _mapper.Map or _mapper.ProjectTo
- }
当然还有很多可扩展性,比如:
定制类型转换器
有时,您需要完全控制从一种类型到另一种类型的转换。通常,这是当一种类型看起来与另一种类型不一样时,已经存在转换函数,并且您希望从“松散”类型变为更强的类型,例如字符串的源类型到Int32的目标类型。
例如,假设我们的源类型为:
- public class Source
- {
- public string Value1 { get; set; }
- public string Value2 { get; set; }
- public string Value3 { get; set; }
- }
但您想将其映射到:
- public class Destination
- {
- public int Value1 { get; set; }
- public DateTime Value2 { get; set; }
- public Type Value3 { get; set; }
- }
如果我们尝试按原样映射这两种类型,则AutoMapper会抛出异常(在映射时和配置检查时),因为AutoMapper不知道从字符串到int,DateTime或Type的任何映射。要为这些类型创建映射,我们必须提供一个自定义类型转换器,并且我们可以通过三种方式:
- void ConvertUsing(Func<TSource, TDestination> mappingFunction);
- void ConvertUsing(ITypeConverter<TSource, TDestination> converter);
- void ConvertUsing<TTypeConverter>() where TTypeConverter : ITypeConverter<TSource, TDestination>;
第一个选项就是任何带有源并返回目的地的函数(也有多个重载)。这适用于简单的情况,但对于较大的情况则显得笨拙。在更困难的情况下,我们可以创建一个自定义的ITypeConverter :
- public interface ITypeConverter<in TSource, TDestination>
- {
- TDestination Convert(TSource source, TDestination destination, ResolutionContext context);
- }
并向AutoMapper提供一个自定义类型转换器的实例,或者为类型提供AutoMapper将在运行时实例化的类型。我们上面的源/目标类型的映射配置将变为:
- public void Example()
- {
- var configuration = new MapperConfiguration(cfg => {
- cfg.CreateMap<string, int>().ConvertUsing(s => Convert.ToInt32(s));
- cfg.CreateMap<string, DateTime>().ConvertUsing(new DateTimeTypeConverter());
- cfg.CreateMap<string, Type>().ConvertUsing<TypeTypeConverter>();
- cfg.CreateMap<Source, Destination>();
- });
- configuration.AssertConfigurationIsValid();
- var source = new Source
- {
- Value1 = "5",
- Value2 = "01/01/2000",
- Value3 = "AutoMapperSamples.GlobalTypeConverters.GlobalTypeConverters+Destination"
- };
- Destination result = mapper.Map<Source, Destination>(source);
- result.Value3.ShouldEqual(typeof(Destination));
- }
- public class DateTimeTypeConverter : ITypeConverter<string, DateTime>
- {
- public DateTime Convert(string source, DateTime destination, ResolutionContext context)
- {
- return System.Convert.ToDateTime(source);
- }
- }
- public class TypeTypeConverter : ITypeConverter<string, Type>
- {
- public Type Convert(string source, Type destination, ResolutionContext context)
- {
- return Assembly.GetExecutingAssembly().GetType(source);
- }
- }
在第一个映射中,从字符串到Int32,我们仅使用内置的Convert.ToInt32函数(作为方法组提供)。接下来的两个使用自定义ITypeConverter实现。
自定义类型转换器的真正强大之处在于,只要AutoMapper在任何映射类型上找到源/目标对,它们就可以使用。我们可以构建一组自定义类型转换器,并在其上使用其他映射配置,而无需任何其他配置。在上面的示例中,我们不必再次指定string / int转换。由于必须在类型成员级别配置自定义值解析器,因此自定义类型转换器的作用域是全局的。
当然还有很多功能需要去实际项目中实现。
相关文章
- 鲜为人知但很有用的 HTML 属性
- 翻转再翻转!有意思的水平横向溢出滚动
- 自定义计数器小技巧!CSS 实现长按点赞累加动画
- 过五关!React高频面试题指南
- 软件开发中的十个认知偏差
- 不需要 JS!仅用 CSS 也能达到监听页面滚动的效果!
- 一文读懂TypeScript类型兼容性
- Vue 的响应式原则与双向数据绑定
- 快速掌握 TypeScript 新语法:Infer Extends
- JWT教你如何证明你是我的人!
- 一篇带给你 V8 GC 的实现
- 面试官:请使用JS完成一个LRU缓存?
- 通过可视化来学习JavaScript事件循环
- 新的跨域策略:使用 COOP、COEP 为浏览器创建更安全的环境
- 为什么有人说 vite 快,有人却说 vite 慢?
- 种草 Vue3 中几个好玩的插件和配置
- 超全面的前端工程化配置指南
- Vue 状态管理未来样子
- Volatile关键字能保证原子性么?
- 面试突击:SpringBoot 有几种读取配置文件的方法?