C#类对象映射AutoMapper
AutoMapper 是 C# 中一款流行的 对象 - 对象映射库,核心作用是简化两个相似结构对象之间的属性赋值操作(例如将领域模型映射为 DTO、将数据实体映射为视图模型等),避免手动编写大量重复的 target.Property = source.Property 代码,提升开发效率并降低维护成本。
一、核心概念
在使用 AutoMapper 前,需理解两个核心角色:
1.源类型(Source Type):数据的来源对象(如代码中的 SignalLightItem)。
2.目标类型(Destination Type):数据的接收对象(如代码中的 SignalLight)。
3.映射配置(Mapping Configuration):定义源类型如何映射到目标类型的规则(是 AutoMapper 工作的核心)。
通过 NuGet 安装AutoMapper包:
通过「映射配置文件」定义规则(推荐)创建继承自
Profile 的类,在构造函数中定义源→目标的映射规则:
using AutoMapper;// 定义映射配置文件(一个 Profile 可包含多个映射规则)public class SignalLightProfile : Profile{ public SignalLightProfile() { // 配置:SignalLightItem(源) → SignalLight(目标) // 1. 若属性名完全一致(如 Name、IsGreen 等),AutoMapper 会自动映射 // 2. 若属性名不一致,需手动指定(你的场景无需此步骤) CreateMap<SignalLightItem, SignalLight>(); }}
var config = new MapperConfiguration(cfg =>{ cfg.CreateMap<SignalLightItem, SignalLight>(); // 直接定义映射});IMapper mapper = config.CreateMapper(); // 创建 IMapper 实例//使用新版库需要使用NullLoggerFactoryIMapper mapper;MapperConfiguration config;config = new MapperConfiguration(cfg =>{ //定义互换映射 cfg.CreateMap<SignalLightItem, SignalLight>().ReverseMap(); // 直接定义映射},new NullLoggerFactory());mapper = config.CreateMapper(); // 创建 IMapper 实例
常见映射场景与高级用法
除了「属性名一致自动映射」,AutoMapper 还支持多种复杂场景:
- 属性名不一致的映射若源类型和目标类型的属性名不同
(如源 UserName → 目标 Name),需通过 ForMember 手动指定:
public class UserProfile : Profile{ public UserProfile() { CreateMap<UserEntity, UserDto>() // 源.UserName → 目标.Name .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.UserName)) // 源.Age → 目标.UserAge(若源为 null,指定默认值 0) .ForMember(dest => dest.UserAge, opt => opt.MapFrom(src => src.Age ?? 0)); }}
- 忽略某些属性若目标类型的某个属性不需要从源类型映射
(如目标的 IsDeleted 字段),可使用 Ignore:
CreateMap<SignalLightItem, SignalLight>() .ForMember(dest => dest.IsDeleted, opt => opt.Ignore()); // 忽略 IsDeleted 属性
- 条件映射
仅当源类型满足特定条件时,才映射某个属性:
CreateMap<SignalLightItem, SignalLight>() // 仅当源的 IsAlways 为 true 时,才映射目标的 IsGreen .ForMember(dest => dest.IsGreen, opt => opt.MapFrom(src => src.IsAlways ? src.IsGreen : false));
- 嵌套对象映射若源类型包含嵌套对象
(如 UserEntity 包含 AddressEntity),目标类型包含对应的嵌套 DTO(UserDto 包含 AddressDto),需先配置嵌套对象的映射:
// 1. 先配置嵌套对象的映射CreateMap<AddressEntity, AddressDto>();// 2. 再配置主对象的映射(AutoMapper 会自动递归映射嵌套对象)CreateMap<UserEntity, UserDto>();
- 自定义类型转换器若源类型和目标类型的转换逻辑复杂
(如 string 转 DateTime、int 转 Enum),可自定义转换器:
// 1. 定义转换器:string(源)→ DateTime(目标)public class StringToDateTimeConverter : IValueConverter<string, DateTime>{ public DateTime Convert(string source, ResolutionContext context) { // 自定义转换逻辑(如处理多种日期格式) return DateTime.TryParse(source, out var result) ? result : DateTime.Now; }}// 2. 在映射中使用转换器CreateMap<OrderEntity, OrderDto>() .ForMember(dest => dest.OrderTime, opt => opt.ConvertUsing(new StringToDateTimeConverter(), src => src.OrderTimeStr));
四、常见错误与解决方案
常见的错误:
错误类型原因解决方案
Missing type map configuration未:配置源→目标的映射规则按步骤 2 配置CreateMap()
NullReferenceException源对象为null,或源对象的嵌套属性为null1. 确保源对象非空;2. 使用MapFrom处理 null 场景(如src => src.NestedProp?.Value ?? “默认值”)
No default constructor目标类型没有无参构造函数(AutoMapper 默认需要无参构造函数创建目标对象)1. 给目标类型添加无参构造函数;2. 若无法添加,使用ConstructUsing自定义目标对象创建逻辑
Property ‘XXX’ is read-only目标类型的属性是只读的(如只有get没有set)1. 给目标属性添加set方法;2. 若为只读属性,使用ForMember结合MapFrom手动赋值(需确保属性可写)
五、总结
1.优先使用 Profile 配置文件:将映射规则集中管理,避免散落在业务代码中。
2.命名规范统一:尽量让源和目标的属性名一致,减少手动配置的工作量。
3.避免过度映射:只映射需要的属性,无关属性使用 Ignore 排除,提升性能。
4.测试映射规则:使用 AutoMapper 提供的
Configuration.AssertConfigurationIsValid() 方法,在启动时校验映射配置是否完整(避免运行时错误):// 在 Program.cs 中校验配置var mapperConfig = new MapperConfiguration(cfg => cfg.AddProfile<SignalLightProfile>());mapperConfig.AssertConfigurationIsValid(); // 校验所有映射规则是否完整
5.依赖注入 IMapper:避免在代码中直接 new Mapper(),通过 DI 容器管理 IMapper 实例,便于测试和扩展。