![Mapster 属性驱动扩展方法生成指南:用 [GenerateMapper] 自动产出 AdaptTo / ProjectTo 映射代码](http://pic.xiahunao.cn/yaotu/Mapster 属性驱动扩展方法生成指南:用 [GenerateMapper] 自动产出 AdaptTo / ProjectTo 映射代码)
Mapster 属性驱动扩展方法生成指南用 [GenerateMapper] 自动产出 AdaptTo / ProjectTo 映射代码【免费下载链接】MapsterA fast, fun and stimulating object to object Mapper项目地址: https://gitcode.com/GitHub_Trending/ma/Mapster导读本文聚焦 Mapster 代码生成工具Mapster.Tool中的属性驱动的扩展方法Extension Methods生成能力你只需在领域模型上标注[AdaptFrom]、[AdaptTo]或[AdaptTwoWays]再叠加一个[GenerateMapper]Mapster.Tool 就会自动为你生成AdaptToDto、AdaptTo(dto)以及ProjectToDto等强类型映射扩展方法与投影表达式。读完本文你将掌握[GenerateMapper]的完整用法、属性参数语义、底层生成逻辑以及如何把它接入csproj构建流程实现标注即映射的零手写 DTO 工作流。一、从注解到扩展方法一次标注三份产出Mapster 代码生成体系提供了三种代码生成风味本篇文章聚焦其中的属性Attribute驱动路线。其核心约定是凡是标注了[AdaptFrom]、[AdaptTo]、[AdaptTwoWays]的 POCO都可以再叠加[GenerateMapper]让工具生成扩展方法区别于只生成 DTO 模型本身的属性驱动 DTO 生成参见 Attribute-based Dto model generation。先看官方示例中最简用法[AdaptTo([name]Dto), GenerateMapper] public class Student { ... }工具扫描到该类型后会同时产出两部分代码生成的StudentDto为[name]Dto展开的结果扩展类按[name]Mapper规则命名为StudentMapperpublic class StudentDto { ... } public static class StudentMapper { // 1. 从源对象生成新目标对象 public static StudentDto AdaptToDto(this Student poco) { ... } // 2. 将源对象映射到已存在的目标对象MapToTarget 语义 public static StudentDto AdaptTo(this Student poco, StudentDto dto) { ... } // 3. 投影表达式可直接用于 EF Core 等 IQueryable 场景 public static ExpressionFuncStudent, StudentDto ProjectToDto ... }也就是说[GenerateMapper]一次为你产出三种能力新建映射AdaptToXxx、合并到既有对象AdaptTo(source, target)与IQueryable 投影表达式ProjectToXxx。三个方向分别对应 Mapster 的MapType.Map、MapType.MapToTarget、MapType.Projection三种映射语义。二、[GenerateMapper] 属性参数详解GenerateMapperAttribute定义于 src/Mapster.Core/Attributes/GenerateMapperAttribute.cs可标注在类、结构体或接口上并暴露以下可配置项参数类型默认值作用Namestring[name]Mapper生成的扩展类名称模板[name]会被替换为源类型名Student→StudentMapperForAttributesType[]null限定仅为指定类型的 Adapt 属性生成扩展方法null表示对该类型上的全部 Adapt 属性生效IsHelperClassboolfalse为true时生成普通静态辅助类调用形态为StudentMapper.AdaptToDto(poco)为false时生成 C# 扩展方法调用形态为poco.AdaptToDto()IsInternalboolfalse生成的扩展类使用internal可见性而非public2.1 用 ForAttributes 精确控制生成范围当同一个类型上存在多个 Adapt 属性时ForAttributes用于挑选只针对其中某类生成扩展方法[AdaptTo([name]Dto)] [AdaptTo([name]Merge)] [GenerateMapper(ForAttributes new[] { typeof(AdaptToAttribute) })] public class Student { public string Name { get; set; } }从源码 src/Mapster.Tool/Program.cs 的GenerateExtensions可以看到工具会以mapperAttr.ForAttributes构造一个集合set再对类型上所有AdaptAttributeBuilder执行set?.Contains(it.GetType()) ! false过滤ForAttributes null时全部保留。底层还提供了GenerateMapperAttributeBuildersrc/Mapster.Core/Register/GenerateMapperAttributeBuilder.cs作为编程式备选可通过ForTypes、ForAllTypesInNamespace、ForTypeT等 fluent 方法批量指定目标类型。2.2 IsHelperClass扩展方法 vs 静态方法IsHelperClass直接决定生成代码的调用形态。在 src/Mapster.Tool/Program.cs 的GenerateExtensionMethods中方法类型被区分为ExpressionTranslator.LambdaType.ExtensionMethod与LambdaType.PublicMethod前者生成为this Student poco开头的扩展方法后者生成为普通静态方法。差异对比// IsHelperClass false默认poco.AdaptToDto() 扩展方法风格 public static StudentDto AdaptToDto(this Student poco) { ... } // IsHelperClass trueStudentMapper.AdaptToDto(poco) 静态方法风格 public static StudentDto AdaptToDto(Student poco) { ... }三、与 Adapt 属性联动映射方向的完整语义[GenerateMapper]本身不声明映射方向方向完全由它配合的 Adapt 属性决定。BaseAdaptAttributesrc/Mapster.Core/Attributes/BaseAdaptAttribute.cs提供了AdaptFromAttribute、AdaptToAttribute、AdaptTwoWaysAttribute与ProjectToAttribute四种子类[AdaptTo([name]Dto)]为Student → StudentDto生成AdaptToDto与ProjectToDto[AdaptFrom([name]Merge)]为反向StudentMerge → Student生成扩展方法方法名中会剥离源类型名以生成AdaptToStudent之类的方法[AdaptTwoWays([name]Dto)]双向生成Student与StudentDto互为源/目标[ProjectTo]只生成投影MapType.Projection适合查询投影场景。此外Adapt 属性还带有一组影响生成结果的参数在属性驱动扩展方法生成中同样生效参数作用IgnoreAttributes排除带有指定特性的成员如[JsonIgnore]IgnoreNoAttributes只保留带有指定特性的成员白名单模式IgnoreNamespaces排除属性类型位于指定命名空间的成员MapType显式声明生成哪些映射方向Map、MapToTarget、Projection的组合MaxDepth限制嵌套对象递归生成的深度IgnoreNullValues为AdaptFrom生成可空属性MapToConstructor为AdaptTo/AdaptTwoWays生成只读属性 构造函数PreserveReference/ShallowCopyForSameType/RequireDestinationMemberSource控制引用保留、同类型浅拷贝与目标成员来源校验以MapType为例默认值为MapType.Map | MapType.MapToTarget即默认生成新建映射与合并映射两种方法加上Projection才会产出ProjectToXxx。相关组合逻辑在 src/Mapster.Tool/Program.cs 中体现为attr.MapType 0 ? MapType.Map | MapType.MapToTarget : attr.MapType的取值判断。3.1 属性类型重定向PropertyType 的叠加效果当生成扩展方法时DTO 中属性类型的推导遵循与 DTO 模型生成相同的规则若属性类型本身也标注了 Adapt 属性则自动转发为其 DTO 类型也可用[PropertyType]src/Mapster.Core/Attributes/PropertyTypeAttribute.cs在类或属性级别强制改写目标类型其ForAttributes参数还能限定只对某类 Adapt 属性生效。因此以下两种写法产出的扩展方法签名一致// 方式一自动转发Enrollment 自带 [AdaptTo]StudentDto.Enrollments 推导为 ICollectionEnrollmentDto [AdaptTo([name]Dto), GenerateMapper] public class Student { public ICollectionEnrollment Enrollments { get; set; } } // 方式二显式重定向 [AdaptTo([name]Dto), GenerateMapper] public class Student { [PropertyType(typeof(ICollectionDataItem))] public ICollectionEnrollment Enrollments { get; set; } }四、命令行与 csproj 集成让生成跑进构建流程4.1 安装工具扩展方法生成由 Mapster.Tool 提供属于其extension子命令# 若已有 dotnet-tools.json 可跳过第一步 dotnet new tool-manifest dotnet tool install Mapster.Tool代码侧仅需轻量依赖Mapster.Core[GenerateMapper]、[AdaptTo]等特性都定义在 Core 程序集中若需要TypeAdapterConfig做高级配置再安装完整版Mapster。工具与依赖的完整安装说明见 Mapster Tool Overview。4.2 extension 子命令选项ExtensionOptions定义于 src/Mapster.Tool/ExtensionOptions.cs与model、mapper命令共享大部分选项短选项长选项必填默认值说明-a--assembly是-待扫描的程序集通常为$(TargetDir)$(ProjectName).dll-o--output否Models输出目录-n--namespace否源类型所在命名空间生成代码的命名空间-p--printFullTypeName否falsePOCO 与 DTO 重名时输出全限定类型名-b--baseNamespace否-基础命名空间用于按子命名空间生成嵌套目录结构-s--skipExisting否false跳过已存在的生成文件增量生成-N--nullableDirective否false在生成文件顶部追加#nullable enable典型手动调用dotnet mapster extension -a bin/Debug/net8.0/MyApp.dll -o Generated -n MyApp.Generated -s4.3 接入 csproj 自动生成将扩展方法生成挂到构建目标中即可实现改模型 → 编译 → 自动重新生成的闭环Target NameMapster AfterTargetsAfterBuild Exec WorkingDirectory$(ProjectDir) Commanddotnet tool restore / Exec WorkingDirectory$(ProjectDir) Commanddotnet mapster model -a quot;$(TargetDir)$(ProjectName).dllquot; / Exec WorkingDirectory$(ProjectDir) Commanddotnet mapster extension -a quot;$(TargetDir)$(ProjectName).dllquot; / Exec WorkingDirectory$(ProjectDir) Commanddotnet mapster mapper -a quot;$(TargetDir)$(ProjectName).dllquot; / /Target如需清理生成物可用如下目标删除所有*.g.csItemGroup Generated Include**\*.g.cs / /ItemGroup Target NameCleanGenerated Delete Files(Generated) / /Target更详细的构建集成、-p全名输出与-b动态命名空间用法可对照 Configuration-based Code generation、Fluent API Code generation 与 Interface-based Code generation。五、源码视角GenerateExtensions 的生成流水线了解底层实现有助于排查为什么没生成之类的问题。在 src/Mapster.Tool/Program.cs 的GenerateExtensions方法中完整流程如下隔离加载程序集通过DeferredDependencyAssemblyLoadContext.LoadAssemblyFrom加载目标程序集避免被扫描程序集与其依赖、Mapster 自身程序集发生类型/框架冲突收集配置config.Scan(assembly)扫描IRegister等注册器codeGenConfig.Scan(assembly)收集全部 Adapt 属性构建器并把config.RuleMap中涉及的泛型具体化类型一并纳入候选类型集合构建专用配置快照为每个BaseAdaptAttribute克隆一份TypeAdapterConfig并应用其IgnoreNullValues、MapToConstructor等设置保证不同属性互不干扰筛选目标类型type.GetGenerateMapperAttributes(codeGenConfig)找到[GenerateMapper]仅当存在该特性或存在带GenerateMapper设置的规则映射时才继续生成方法体GenerateExtensionMethods按MapType位标记分别调用config.CreateMapExpression将Map生成为AdaptTo 目标类型友好名的扩展方法、MapToTarget生成为AdaptTo(source, target)、Projection生成为ProjectTo 目标类型友好名的公开 Lambda 属性。其中方法名的构造规则是destName.Replace(entityType.Name, )——即方法名由AdaptTo 去掉源类型名后的目标类型名组成因此Student → StudentDto得到AdaptToDto而StudentDto → Student得到AdaptToStudent。六、实战样例与验证仓库中的 src/Sample.CodeGen 是完整的属性驱动代码生成示例。其Domains/Student.cs标注了映射属性生成的 DTO 与映射代码位于Models/与Mappers/目录。可参考 src/Sample.CodeGen/Models/StudentDto.g.cs 观察 DTO 形态以及 src/Sample.CodeGen/Mappers/StudentMapper.g.cs 观察接口驱动生成的Map方法与StudentProjection表达式——同一套config.CreateMapExpression机制保证了不同生成风味产出的代码语义完全一致。验证方式很简单在标注[AdaptTo([name]Dto), GenerateMapper]后运行dotnet mapster extension -a 程序集路径若输出目录出现StudentMapper.g.cs且其中包含AdaptToDto、AdaptTo(this Student, StudentDto)与ProjectToDto三个成员即表示生成成功。七、常见问题与限制方法未生成检查[GenerateMapper]所在类型是否同时存在 Adapt 属性ForAttributes是否与 Adapt 属性类型匹配MapType是否包含期望的方向默认不含Projection需要ProjectTo时需显式声明。-a指定的程序集找不到依赖Mapster.Tool 8.4.1 及以后版本若报System.IO.FileNotFoundException可在 csproj 中加CopyLocalLockFileAssembliestrue/CopyLocalLockFileAssemblies或改用dotnet build -p:CopyLocalLockFileAssembliestrue详见 Mapster Tool Overview 的 Troubleshooting 一节。POCO 与 DTO 重名为extension命令添加-p参数生成代码将输出全限定类型名以避免歧义。[GenerateMapper]仅适用于类、结构体与接口这是其AttributeUsage的限制不要尝试标注在方法或属性上。总结[GenerateMapper]是 Mapster 属性驱动代码生成体系的最后一公里Adapt 属性负责描述 DTO 结构与映射方向[GenerateMapper]负责把映射声明落成可直接调用的强类型代码。三者配合csproj构建钩子即可实现领域模型标注即映射的完全自动化流程同时保留MapType、ForAttributes、IsHelperClass等细粒度控制面兼顾灵活性与零运行时反射开销。【免费下载链接】MapsterA fast, fun and stimulating object to object Mapper项目地址: https://gitcode.com/GitHub_Trending/ma/Mapster创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考