在 C# 项目中,实体、视图模型、数据传输对象之间经常需要互相转换。如果每一次转换都依靠人工逐属性赋值,代码会变得重复且容易遗漏字段。AutoMapper 的核心价值在于把这种重复劳动从业务代码中抽离出来,通过声明式配置完成源对象到目标对象的属性复制。它既能自动识别同名属性,也能通过映射规则处理类型转换、字段改名、条件赋值、自定义解析等复杂情况,使对象映射逻辑集中、可读、可维护。

对象映射的基本问题与 AutoMapper 的定位
很多 C# 项目都会出现类似场景:数据库实体需要转换为接口返回的数据传输对象,前端提交的请求对象又需要转换为持久化对象。若实体字段较多,手动赋值不仅冗长,还会在字段新增或重命名时产生大量修改点。AutoMapper 通过映射配置把源类型和目标类型绑定起来,运行时由映射引擎根据规则生成目标实例,从而减少样板代码。
在使用 AutoMapper 时,通常先安装相关包,再定义 Profile 类。Profile 是映射配置的载体,其中 CreateMap 方法负责声明源类型与目标类型之间的关系。对于名称相同的属性,AutoMapper 会尽量自动匹配;对于名称不同或类型不同的属性,则需要进一步配置。这种设计让简单场景保持简洁,也让复杂场景拥有明确的扩展入口。
在依赖注入容器中注册 AutoMapper 后,业务服务可以通过 IMapper 接口获取映射器实例。这样映射器成为应用基础设施的一部分,而不是散落在各处的一次性工具。以下示例先定义两个用户对象,它们包含同名属性,也包含需要特殊处理的属性,为后续配置提供基础。
using System;
using AutoMapper;
// 源实体
public class UserSource
{
public int Id { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public DateTime CreateTime { get; set; }
public int Status { get; set; }
}
// 目标实体
public class UserDestination
{
public int Id { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string CreateTimeStr { get; set; }
public string StatusDesc { get; set; }
}
从自动匹配到自定义字段与条件映射
基础映射通常从 CreateMap 开始。它告诉 AutoMapper 一个源类型可以转换为目标类型。若源对象和目标对象的属性名一致,例如 Id、UserName、Email,映射器会直接复制值。对于 CreateTime 到 CreateTimeStr 这种名称不同且类型从 DateTime 转为 string 的情况,需要使用 ForMember 指定目标成员,并通过 MapFrom 提供取值表达式。
ForMember 是字段级映射的核心方法。它允许开发者精确控制某个目标属性如何从源对象中取得值。表达式中可以调用字符串格式化、枚举转换、简单计算等方法,但不建议把复杂业务逻辑全部塞入映射配置。若某个字段只在满足条件时才需要写入,可以结合 Condition 方法设置判断条件,避免空值或非法值覆盖目标对象中的已有内容。
当字段转换逻辑具有复用价值时,自定义值解析器是更合适的方案。实现 IValueResolver 接口后,可以把解析逻辑封装为独立类,再在 Profile 中通过 MapFrom<UserStatusResolver>() 引入。这样不仅让 Profile 更简洁,也便于单元测试和跨映射复用。下面的示例分别展示服务注册、字段映射、条件映射和值解析器配置。
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using AutoMapper;
// 基础映射配置
public class UserBasicProfile : Profile
{
public UserBasicProfile()
{
CreateMap<UserSource, UserDestination>();
}
}
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAutoMapper(typeof(UserBasicProfile));
var app = builder.Build();
app.Run();
}
}
// 业务服务中注入映射器
public class UserService
{
private readonly IMapper _mapper;
public UserService(IMapper mapper)
{
_mapper = mapper;
}
public UserDestination GetUserDestination(UserSource source)
{
return _mapper.Map<UserDestination>(source);
}
}
using System;
using AutoMapper;
// 自定义字段映射与条件映射
public class UserFieldProfile : Profile
{
public UserFieldProfile()
{
CreateMap<UserSource, UserDestination>()
// 将 DateTime 转换为指定格式的字符串
.ForMember(dest => dest.CreateTimeStr,
opt => opt.MapFrom(src => src.CreateTime.ToString("yyyy-MM-dd")))
// 仅在源对象 Email 非空时映射
.ForMember(dest => dest.Email,
opt =>
{
opt.Condition(src => !string.IsNullOrEmpty(src.Email));
opt.MapFrom(src => src.Email);
});
}
}
using System;
using AutoMapper;
// 自定义值解析器
public class UserStatusResolver : IValueResolver<UserSource, UserDestination, string>
{
public string Resolve(UserSource source, UserDestination destination, string destMember, ResolutionContext context)
{
return source.Status == 1 ? "启用" : "禁用";
}
}
// 在 Profile 中使用值解析器
public class UserResolverProfile : Profile
{
public UserResolverProfile()
{
CreateMap<UserSource, UserDestination>()
.ForMember(dest => dest.StatusDesc,
opt => opt.MapFrom<UserStatusResolver>());
}
}
映射钩子、集合反向映射与工程校验
除了字段级规则,AutoMapper 还提供映射前后钩子。BeforeMap 适合在映射开始前对源对象做轻量修正,例如补全默认值;AfterMap 适合在映射结束后补充目标对象中无法直接由源对象派生的字段。使用钩子时要保持克制,因为映射器的职责是转换,而不是承载完整业务流程。若逻辑过重,应抽到独立服务中,再在钩子中调用。
集合映射是日常开发中的高频需求。AutoMapper 支持 List、IEnumerable 等集合类型的映射,只要元素类型已经配置好映射规则,集合整体即可转换。若业务中还需要从目标对象还原源对象,可以使用 ReverseMap 开启反向映射,减少重复配置。反向映射同样会继承正向映射中可复用的字段规则,但遇到单向转换逻辑时仍需单独处理。
在工程实践中,映射配置应当按模块拆分,避免一个 Profile 无限膨胀。映射规则应保持稳定,复杂业务变化应放在服务层或领域层处理。启动阶段执行 AssertConfigurationIsValid 配置校验,可以在部署早期发现未映射成员、类型不匹配等问题,降低运行时故障概率。下面的示例展示映射钩子、集合与反向映射,以及启动校验的写法。
using System;
using AutoMapper;
// 映射前后钩子
public class UserHookProfile : Profile
{
public UserHookProfile()
{
CreateMap<UserSource, UserDestination>()
// 映射前补充默认值
.BeforeMap((src, dest) =>
{
if (string.IsNullOrEmpty(src.UserName))
{
src.UserName = "默认用户";
}
})
// 映射后补充目标字段
.AfterMap((src, dest) =>
{
dest.CreateTimeStr = src.CreateTime.ToString("yyyy年MM月dd日");
});
}
}
using System.Collections.Generic;
using AutoMapper;
// 反向映射配置
public class UserReverseProfile : Profile
{
public UserReverseProfile()
{
CreateMap<UserSource, UserDestination>().ReverseMap();
}
}
// 集合映射与反向映射使用示例
public class UserCollectionService
{
private readonly IMapper _mapper;
public UserCollectionService(IMapper mapper)
{
_mapper = mapper;
}
public List<UserDestination> MapToList(List<UserSource> sourceList)
{
return _mapper.Map<List<UserDestination>>(sourceList);
}
public UserSource MapBack(UserDestination destination)
{
return _mapper.Map<UserSource>(destination);
}
}
using Microsoft.Extensions.DependencyInjection;
using AutoMapper;
// 启动时校验映射配置
public class StartupValidation
{
public static void Validate(IServiceCollection services)
{
using var scope = services.CreateScope();
var mapper = scope.ServiceProvider.GetRequiredService<IMapper>();
mapper.ConfigurationProvider.AssertConfigurationIsValid();
}
}
综合来看,AutoMapper 适合处理重复、机械、结构化的对象转换工作。掌握 CreateMap、ForMember、Condition、值解析器、BeforeMap、AfterMap、集合映射和 ReverseMap 后,可以覆盖大多数 C# 项目中的对象映射需求。实际使用时,建议保持配置清晰、职责单一,并在启动阶段完成校验,让映射层成为稳定可靠的基础设施。
AutoMapperC#对象映射映射配置修改时间:2026-07-12 21:27:16