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 实例//使用新版库需要使用NullLoggerFactory
IMapper 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<Source, Destination>()
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 实例,便于测试和扩展。