增量生成器管道 API 完整参考
深入理解增量生成器的管道模式、数据流转换和性能优化
📋 文档信息
| 属性 | 值 |
|---|---|
| 难度 | 高级 |
| 阅读时间 | 60 分钟 |
| 前置知识 | 源生成器基础、LINQ、函数式编程 |
| 相关文档 | 增量生成器基础 |
🎯 学习目标
完成本系列文档后,你将能够:
- ✅ 理解增量生成器的管道模式
- ✅ 掌握各种管道操作(Select、Where、Combine 等)
- ✅ 理解数据流转换和缓存机制
- ✅ 优化增量生成器的性能
- ✅ 调试和诊断管道问题
- ✅ 应用高级管道模式
📚 文档列表
本系列文档分为以下几个部分:
| 文档 | 说明 | 难度 |
|---|---|---|
| 数据流转换 | IncrementalValueProvider 和 IncrementalValuesProvider | 中级 |
| 缓存机制 | 缓存原理、IEquatable 实现 | 高级 |
| 性能优化 | 性能优化最佳实践 | 高级 |
| 调试管道 | 调试技巧和日志记录 | 中级 |
| 高级管道操作 | 复杂管道模式和实战案例 | 高级 |
| 最佳实践 | 最佳实践和反模式 | 中级 |
🚀 快速开始
什么是增量生成器管道?
增量生成器使用管道模式处理数据,每个操作都会创建一个新的 Provider。管道的核心优势是:
- 增量计算: 只有当输入改变时才重新计算
- 缓存机制: 自动缓存中间结果
- 并行处理: 可以并行处理多个数据项
- 类型安全: 编译时类型检查
基本管道示例
csharp
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// 1. 创建数据源
var classDeclarations = context.SyntaxProvider
.CreateSyntaxProvider(
predicate: (node, _) => node is ClassDeclarationSyntax,
transform: (ctx, _) => ctx.Node as ClassDeclarationSyntax);
// 2. 转换数据
var classNames = classDeclarations
.Select((classDecl, _) => classDecl?.Identifier.Text);
// 3. 过滤数据
var publicClasses = classDeclarations
.Where((classDecl, _) =>
classDecl.Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword)));
// 4. 注册输出
context.RegisterSourceOutput(publicClasses, (spc, classDecl) =>
{
var code = GenerateCode(classDecl);
spc.AddSource($"{classDecl.Identifier.Text}.g.cs", code);
});
}📊 管道操作概览
核心操作
| 操作 | 说明 | 输入 | 输出 |
|---|---|---|---|
| Select | 转换数据 | T | U |
| Where | 过滤数据 | T | T |
| Combine | 组合两个 Provider | T, U | (T, U) |
| Collect | 收集到集合 | T (多个) | ImmutableArray<T> |
| SelectMany | 展开为多个元素 | T | U (多个) |
管道执行流程
🔑 关键概念
IncrementalValueProvider vs IncrementalValuesProvider
csharp
// IncrementalValueProvider<T> - 单个值
IncrementalValueProvider<Compilation> compilation =
context.CompilationProvider;
// IncrementalValuesProvider<T> - 多个值
IncrementalValuesProvider<ClassDeclarationSyntax> classes =
context.SyntaxProvider.CreateSyntaxProvider(...);缓存机制
增量生成器的核心优势是缓存。只有当输入改变时,才会重新计算:
csharp
// 定义可缓存的数据结构
public record ClassInfo(
string Name,
string Namespace,
ImmutableArray<string> Properties);
// 只有当 ClassInfo 改变时才会重新生成代码
context.RegisterSourceOutput(classInfos, (spc, info) =>
{
var code = GenerateCode(info);
spc.AddSource($"{info.Name}.g.cs", code);
});📖 学习路径
初学者路径
进阶路径
调试路径
💡 快速参考
常用操作速查
csharp
// Select - 转换数据
var names = classes.Select((c, _) => c.Identifier.Text);
// Where - 过滤数据
var publicClasses = classes.Where((c, _) => c.Modifiers.Any(...));
// Combine - 组合数据
var combined = classes.Combine(compilation);
// Collect - 收集到集合
var allClasses = classes.Collect();
// SelectMany - 展开
var methods = classes.SelectMany((c, _) => c.Members.OfType<MethodDeclarationSyntax>());性能优化速查
csharp
// ✅ 使用 record 类型
public record ClassData(string Name, string Namespace);
// ✅ 使用 ImmutableArray
public record ClassData(string Name, ImmutableArray<string> Properties);
// ✅ 实现 IEquatable
public record ClassData(...) : IEquatable<ClassData> { }
// ✅ 避免重复计算
var cached = compilation.Select((c, _) => ExpensiveOperation());🎓 实战案例
案例 1: 生成 DTO 映射
csharp
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// 1. 查找标记了 [GenerateMapper] 的类
var mapperClasses = context.SyntaxProvider
.ForAttributeWithMetadataName(
"GenerateMapperAttribute",
predicate: (node, _) => node is ClassDeclarationSyntax,
transform: (ctx, _) => GetMapperInfo(ctx));
// 2. 过滤掉 null
var validMappers = mapperClasses
.Where((info, _) => info != null);
// 3. 生成代码
context.RegisterSourceOutput(validMappers, (spc, info) =>
{
var code = GenerateMapperCode(info);
spc.AddSource($"{info.SourceType}Mapper.g.cs", code);
});
}案例 2: 收集所有类名
csharp
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// 1. 获取所有类名
var classNames = context.SyntaxProvider
.CreateSyntaxProvider(
predicate: (node, _) => node is ClassDeclarationSyntax,
transform: (ctx, _) =>
((ClassDeclarationSyntax)ctx.Node).Identifier.Text);
// 2. 收集到一个集合
var allClassNames = classNames.Collect();
// 3. 生成包含所有类名的代码
context.RegisterSourceOutput(allClassNames, (spc, names) =>
{
var code = GenerateClassListCode(names);
spc.AddSource("AllClasses.g.cs", code);
});
}🔗 相关资源
官方文档
相关指南
示例项目
- ToString 生成器 - 实用示例
- Builder 生成器 - 复杂示例
🚀 下一步
最后更新: 2026-02-05