Facet
编译时零开销的 C# DTO 生成器,通过 [Facet] 注解自动生成构造函数、LINQ 投影与反向映射
加载项目详情…
本应用为开源项目,仅供学习研究,请遵守其开源协议。
编译时零开销的 C# DTO 生成器,通过 [Facet] 注解自动生成构造函数、LINQ 投影与反向映射
加载项目详情…
本应用为开源项目,仅供学习研究,请遵守其开源协议。
在企业级 .NET 开发中,DTO(Data Transfer Object)地狱是每个团队都绕不开的痛点。一个包含 20 个字段的 UserEntity 要转成 UserDto——你得写构造函数、做属性映射、处理 DateTime 格式、照顾可空字段、还得写反向映射回 Entity 的方法。字段一多,光一个实体对的 Mapper 就得写上百行,而且每次字段增减都要手动同步。
Facet 正是为解决这一痛点而生。这是一个 C# 源代码生成器(Source Generator),通过编译时代码生成,将 DTO 映射的重复劳动压缩到极致:开发者只需在领域模型上添加几行注解,编译器就会自动生成对应的构造函数、LINQ 投影表达式和反向映射逻辑——全部在编译时完成,运行时零额外开销。
Facet 由独立开发者 Tim Maes 创建和维护。Tim Maes 是 .NET 生态的深度参与者,长期活跃于 GitHub 和博客社区,曾在 .NET 官方博客及 Medium 等平台发表过多篇关于 C# 源代码生成技术的深度教程。
该项目的核心理念来自一个朴素的观察:DDD(领域驱动设计)实践中,领域模型(Entity)需要在不同层次之间流转——持久化层、API 层、前端消费层——每层都需要不同的视图,传统做法是手写大量转换代码,不仅繁琐且极易出错。Facet 将这个过程自动化,让「一个领域模型,多个 Facet 视图」的理念真正落地。
截至目前,该项目已获得 1200+ GitHub Stars,被收录于 NuGet 官方包目录,月下载量持续增长,在 .NET/C# 源码生成器细分领域具有较高的社区认可度。
Facet 的技术基础是 C# Source Generator,这是 .NET 5(2020年)引入的编译器 API,允许在编译期间读取用户的代码并生成新的源文件,生成的代码直接嵌入到编译输出中,无需额外的构建步骤或 IL 注入。
具体来说,Facet 在编译时:
[Facet] 特性的类,分析其属性和方法签名partial class 和成员(构造函数、投影表达式、反向映射器)这意味着 Facet 生成的代码完全可调试、无反射开销、AOT 友好——与运行时反射型 ORM(如 AutoMapper)有本质区别。
| 产物 | 说明 |
|---|---|
| 构造函数 | 从源类型直接构造 Facet 实例 |
| LINQ 投影表达式 | 生成 .Select(x => new Facet { ... }) 表达式树,用于 EF Core 查询投影 |
| 反向映射(ToSource) | 将 Facet 实例的数据同步回源实体 |
| Copy 构造器 | 克隆 Facet 实例 |
| Equality 成员 | 自动生成 Equals()、GetHashCode()、==/!= |
// 领域模型
[Facet]
public partial class UserEntity { }
// 自动生成:
// - partial class UserEntity
// - UserEntity(UserEntity source) 构造函数
// - ToSource() 反向映射方法
// - LINQ 投影表达式
Facet 自动处理枚举到 string 或 int 的转换,并支持可空类型。生成的 API DTO 中,枚举自动转为字符串,前端可直接使用,日期字段的 null 状态也被妥善保留。
在 .NET 企业应用中最实用的场景是与 Entity Framework Core 集成。传统做法中,EF Core 查询返回完整实体后,再在内存中做 DTO 映射,造成不必要的内存分配。Facet 通过生成编译时的 LINQ 投影表达式,让数据库查询直接投影为目标 DTO 形状:
// 查询时直接投影为 UserDto,数据库只返回需要的字段
var userDtos = await _dbContext.Users
.Select(u => u.ToFacet<UserDto>())
.ToListAsync();
这不仅减少了内存分配,还允许数据库层面做列裁剪(Column Pruning),显著提升查询性能。
Facet 支持异步并行映射,适合批量数据处理场景:
var userDtos = await users.ToFacetsParallelAsync(mapper);
通过 [MapFrom] 和 [MapWhen] 注解,可以精细控制每个属性的映射行为,实现条件映射和自定义转换逻辑。
Facet 最适合以下场景:
对于脚本工具、小型工具类项目,Facet 带来的收益有限,手写映射可能更直接。
Facet 代表了 .NET 生态中「编译时代码生成」这一技术路线的成熟化落地。它用注解驱动的方式,将 DTO 映射这类机械性工作彻底自动化,让开发者把精力聚焦在真正的业务逻辑上。作为一个 1200+ Stars 的活跃开源项目,Facet 在 NuGet 上的持续增长反映了 .NET 开发者对编译时元编程的强烈需求。
如果你的团队正在构建 .NET 后端服务且被 DTO 映射所困扰,Facet 值得一试——一行 [Facet] 注解,换来的是编译时保证的正确性和运行时零开销的性能。
分析时间:2026-08-16 | 项目:Tim-Maes/Facet | Stars:1202 | License:MIT