AutoMapper 是一个对象-对象映射器,能够将一个对象映射到另外一个对象。app
用来解决一个看似复杂的问题,这种类型的代码编写起来至关枯燥乏味,编辑器
官网地址:函数
http://automapper.org/spa
官方文档:code
https://docs.automapper.org/en/latest/对象
AutoMapper支持使用静态服务位置构造“自定义值解析器”,“自定义类型转换器”和“值转换器”的功能:blog
var configuration = new MapperConfiguration(cfg => { cfg.ConstructServicesUsing(ObjectFactory.GetInstance); cfg.CreateMap<Source, Destination>(); });
或动态服务位置,用于基于实例的容器(包括子容器/嵌套容器):作用域
var mapper = new Mapper(configuration, childContainer.GetInstance); var dest = mapper.Map<Source, Destination>(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 <TSource,TDestination>:
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转换。因为必须在类型成员级别配置自定义值解析器,所以自定义类型转换器的做用域是全局的。
固然还有不少功能须要去实际项目中实现。