Skip to content

增量生成器管道 API 完整参考

深入理解增量生成器的管道模式、数据流转换和性能优化

📋 文档信息

属性
难度高级
阅读时间60 分钟
前置知识源生成器基础、LINQ、函数式编程
相关文档增量生成器基础

🎯 学习目标

完成本系列文档后,你将能够:

  • ✅ 理解增量生成器的管道模式
  • ✅ 掌握各种管道操作(Select、Where、Combine 等)
  • ✅ 理解数据流转换和缓存机制
  • ✅ 优化增量生成器的性能
  • ✅ 调试和诊断管道问题
  • ✅ 应用高级管道模式

📚 文档列表

本系列文档分为以下几个部分:

文档说明难度
数据流转换IncrementalValueProvider 和 IncrementalValuesProvider中级
缓存机制缓存原理、IEquatable 实现高级
性能优化性能优化最佳实践高级
调试管道调试技巧和日志记录中级
高级管道操作复杂管道模式和实战案例高级
最佳实践最佳实践和反模式中级

🚀 快速开始

什么是增量生成器管道?

增量生成器使用管道模式处理数据,每个操作都会创建一个新的 Provider。管道的核心优势是:

  1. 增量计算: 只有当输入改变时才重新计算
  2. 缓存机制: 自动缓存中间结果
  3. 并行处理: 可以并行处理多个数据项
  4. 类型安全: 编译时类型检查

基本管道示例

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转换数据TU
Where过滤数据TT
Combine组合两个 ProviderT, U(T, U)
Collect收集到集合T (多个)ImmutableArray<T>
SelectMany展开为多个元素TU (多个)

管道执行流程


🔑 关键概念

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);
});

📖 学习路径

初学者路径

  1. 阅读 管道操作详解 - 了解基本操作
  2. 阅读 数据流转换 - 理解数据流
  3. 阅读 最佳实践 - 学习最佳实践

进阶路径

  1. 阅读 缓存机制 - 深入理解缓存
  2. 阅读 性能优化 - 优化性能
  3. 阅读 高级管道操作 - 掌握高级模式

调试路径

  1. 阅读 调试管道 - 学习调试技巧
  2. 阅读 最佳实践 - 避免常见错误

💡 快速参考

常用操作速查

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);
    });
}

🔗 相关资源

官方文档

相关指南

示例项目


🚀 下一步


最后更新: 2026-02-05

基于 MIT 许可发布