Skip to content

Roslyn API 介绍

📋 文档信息

难度: 🟢 简单
预计阅读时间: 30 分钟
前置知识:

  • C# 基础语法
  • 理解源生成器原理

适合人群:

  • 准备开发源生成器的开发者
  • 需要了解 Roslyn API 的开发者

📋 快速导航

章节难度阅读时间链接
核心命名空间🟢5 分钟查看
生成器接口🟢15 分钟查看
API 概览🟡10 分钟查看

🎯 概览

本文档介绍 Roslyn API 的核心概念和生成器接口,包括命名空间、ISourceGenerator、IIncrementalGenerator 和 ForAttributeWithMetadataName 等关键 API。

本文档涵盖:

  • Roslyn 核心命名空间和包引用
  • 传统生成器接口 (ISourceGenerator)
  • 增量生成器接口 (IIncrementalGenerator) - 推荐使用
  • .NET 7+ 高性能 API (ForAttributeWithMetadataName)

典型应用场景:

  • 选择合适的生成器接口
  • 理解生成器的生命周期
  • 掌握基本的 API 使用方法

核心命名空间

必需的命名空间

csharp
using Microsoft.CodeAnalysis;              // 核心抽象(ISymbol, Compilation, SyntaxTree 等)
using Microsoft.CodeAnalysis.CSharp;       // C# 特定实现(CSharpCompilation, CSharpSyntaxTree 等)
using Microsoft.CodeAnalysis.CSharp.Syntax; // C# 语法节点(ClassDeclarationSyntax, MethodDeclarationSyntax 等)
using Microsoft.CodeAnalysis.Text;         // 文本处理(SourceText, TextSpan 等)
using System.Collections.Immutable;        // 不可变集合(ImmutableArray 等)

命名空间说明

  • Microsoft.CodeAnalysis: 包含所有语言通用的核心抽象,如符号(ISymbol)、编译(Compilation)、诊断(Diagnostic)等
  • Microsoft.CodeAnalysis.CSharp: C# 语言特定的实现,包括 C# 编译器和语法树
  • Microsoft.CodeAnalysis.CSharp.Syntax: C# 语法节点的具体类型,每种语法结构都有对应的类
  • Microsoft.CodeAnalysis.Text: 文本处理相关的类型,用于处理源代码文本
  • System.Collections.Immutable: Roslyn 大量使用不可变集合以确保线程安全和性能

NuGet 包引用

xml
<ItemGroup>
  <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" PrivateAssets="all" />
  <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="all" />
</ItemGroup>

生成器接口

ISourceGenerator (传统生成器)

概述

传统的源生成器接口,在 .NET 5 中引入。虽然功能完整,但性能不如增量生成器。

适用场景:

  • 简单的代码生成任务
  • 不需要频繁重新生成
  • 学习和原型开发

完整示例

csharp
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using System.Collections.Generic;
using System.Linq;
using System.Text;

[Generator]
public class MyGenerator : ISourceGenerator
{
    /// <summary>
    /// 初始化生成器
    /// 在编译开始时调用一次,用于注册回调和设置生成器
    /// </summary>
    public void Initialize(GeneratorInitializationContext context)
    {
        // 1. 注册语法接收器(用于收集感兴趣的语法节点)
        context.RegisterForSyntaxNotifications(() => new MySyntaxReceiver());
        
        // 2. 注册后初始化回调(用于生成在整个编译过程中都需要的代码)
        context.RegisterForPostInitialization(ctx => {
            // 生成特性定义
            ctx.AddSource("MyAttribute.g.cs", SourceText.From(@"
using System;

namespace MyNamespace
{
    [AttributeUsage(AttributeTargets.Class)]
    internal class MyAttribute : Attribute { }
}", Encoding.UTF8));
        });
    }
    
    /// <summary>
    /// 执行代码生成
    /// 在编译过程中被调用,可以访问完整的编译信息
    /// </summary>
    public void Execute(GeneratorExecutionContext context)
    {
        // 1. 访问编译信息
        Compilation compilation = context.Compilation;
        
        // 2. 获取语法接收器收集的节点
        if (context.SyntaxReceiver is not MySyntaxReceiver receiver)
            return;
        
        // 3. 遍历收集的类
        foreach (var classDecl in receiver.CandidateClasses)
        {
            // 获取语义模型
            var model = compilation.GetSemanticModel(classDecl.SyntaxTree);
            var classSymbol = model.GetDeclaredSymbol(classDecl);
            
            if (classSymbol == null)
                continue;
            
            // 检查是否有目标特性
            if (!classSymbol.GetAttributes().Any(a => 
                a.AttributeClass?.Name == "MyAttribute"))
                continue;
            
            // 4. 生成代码
            string code = GenerateCode(classSymbol);
            
            // 5. 添加生成的源文件
            context.AddSource($"{classSymbol.Name}.g.cs", SourceText.From(code, Encoding.UTF8));
        }
    }
    
    private string GenerateCode(INamedTypeSymbol classSymbol)
    {
        var sb = new StringBuilder();
        sb.AppendLine($"// Generated for {classSymbol.Name}");
        sb.AppendLine($"namespace {classSymbol.ContainingNamespace}");
        sb.AppendLine("{");
        sb.AppendLine($"    partial class {classSymbol.Name}");
        sb.AppendLine("    {");
        sb.AppendLine("        // Generated members");
        sb.AppendLine("    }");
        sb.AppendLine("}");
        return sb.ToString();
    }
}

/// <summary>
/// 语法接收器 - 用于在语法遍历过程中收集感兴趣的节点
/// </summary>
class MySyntaxReceiver : ISyntaxReceiver
{
    public List<ClassDeclarationSyntax> CandidateClasses { get; } = new();
    
    /// <summary>
    /// 对每个语法节点调用
    /// 注意:这个方法会被调用数千次,必须非常快
    /// </summary>
    public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
    {
        // 只收集带有特性的类
        if (syntaxNode is ClassDeclarationSyntax classDecl &&
            classDecl.AttributeLists.Count > 0)
        {
            CandidateClasses.Add(classDecl);
        }
    }
}

关键成员

GeneratorInitializationContext:

csharp
// 注册语法接收器
void RegisterForSyntaxNotifications(SyntaxReceiverCreator creator);

// 注册后初始化回调
void RegisterForPostInitialization(Action<GeneratorPostInitializationContext> callback);

GeneratorExecutionContext:

csharp
// 编译信息
Compilation Compilation { get; }

// 语法接收器
ISyntaxReceiver? SyntaxReceiver { get; }

// 取消令牌
CancellationToken CancellationToken { get; }

// 添加源文件
void AddSource(string hintName, SourceText sourceText);
void AddSource(string hintName, string source);

// 报告诊断
void ReportDiagnostic(Diagnostic diagnostic);

// 解析选项
ParseOptions ParseOptions { get; }

// 分析器配置选项
AnalyzerConfigOptionsProvider AnalyzerConfigOptions { get; }

// 附加文件
ImmutableArray<AdditionalText> AdditionalFiles { get; }

IIncrementalGenerator (增量生成器 - 推荐)

概述

增量源生成器是 .NET 6 引入的新接口,提供了显著的性能改进。通过管道模式和缓存机制,只在必要时重新生成代码。

优势:

  • 性能: 比传统生成器快 10-100 倍
  • 🔄 增量更新: 只重新生成受影响的部分
  • 💡 IDE 支持: 实时反馈,修改代码时立即看到效果
  • 🎯 精确缓存: 每个管道阶段都可以被缓存

适用场景:

  • 所有生产环境的源生成器
  • 需要频繁重新生成的场景
  • 大型项目

完整示例

csharp
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Collections.Immutable;
using System.Linq;

[Generator]
public class MyIncrementalGenerator : IIncrementalGenerator
{
    public void Initialize(IncrementalGeneratorInitializationContext context)
    {
        // ============================================================
        // 步骤 1: 注册后初始化输出(生成特性定义)
        // ============================================================
        context.RegisterPostInitializationOutput(ctx => {
            ctx.AddSource("MyAttribute.g.cs", @"
using System;

namespace MyNamespace
{
    [AttributeUsage(AttributeTargets.Class)]
    internal class MyAttribute : Attribute 
    {
        public string Name { get; set; }
    }
}");
        });
        
        // ============================================================
        // 步骤 2: 创建语法提供者管道(两阶段过滤)
        // ============================================================
        var classDeclarations = context.SyntaxProvider
            .CreateSyntaxProvider(
                // 第一阶段:语法过滤(快速,不需要语义模型)
                predicate: static (node, _) => IsSyntaxTargetForGeneration(node),
                
                // 第二阶段:语义转换(精确,使用语义模型)
                transform: static (ctx, _) => GetSemanticTargetForGeneration(ctx))
            
            // 过滤掉 null 值
            .Where(static m => m is not null);
        
        // ============================================================
        // 步骤 3: 注册源输出
        // ============================================================
        context.RegisterSourceOutput(classDeclarations,
            static (spc, classInfo) => Execute(classInfo!, spc));
    }
    
    /// <summary>
    /// 语法过滤:快速检查语法结构
    /// 这个方法会被调用数千次,必须非常快
    /// </summary>
    static bool IsSyntaxTargetForGeneration(SyntaxNode node)
    {
        // 只关注带有特性的类
        return node is ClassDeclarationSyntax { AttributeLists.Count: > 0 };
    }
    
    /// <summary>
    /// 语义转换:使用语义模型进行精确验证和数据提取
    /// 只对通过语法过滤的节点调用
    /// </summary>
    static ClassInfo? GetSemanticTargetForGeneration(GeneratorSyntaxContext context)
    {
        var classDecl = (ClassDeclarationSyntax)context.Node;
        var classSymbol = context.SemanticModel.GetDeclaredSymbol(classDecl) as INamedTypeSymbol;
        
        if (classSymbol == null)
            return null;
        
        // 检查是否有目标特性
        var attribute = classSymbol.GetAttributes()
            .FirstOrDefault(a => a.AttributeClass?.Name == "MyAttribute");
        
        if (attribute == null)
            return null;
        
        // 提取特性参数
        string? name = null;
        foreach (var namedArg in attribute.NamedArguments)
        {
            if (namedArg.Key == "Name" && namedArg.Value.Value is string nameValue)
            {
                name = nameValue;
            }
        }
        
        // 返回轻量级数据模型(不要返回 ISymbol 或 SyntaxNode)
        return new ClassInfo(
            classSymbol.Name,
            classSymbol.ContainingNamespace.ToDisplayString(),
            name);
    }
    
    /// <summary>
    /// 生成代码
    /// </summary>
    static void Execute(ClassInfo classInfo, SourceProductionContext context)
    {
        var code = $@"
namespace {classInfo.Namespace}
{{
    partial class {classInfo.ClassName}
    {{
        public string GetGeneratedName() => ""{classInfo.AttributeName ?? "Default"}"";
    }}
}}";
        
        context.AddSource($"{classInfo.ClassName}.g.cs", code);
    }
}

// 轻量级数据模型(使用 record 确保值语义)
record ClassInfo(string ClassName, string Namespace, string? AttributeName);

关键成员

IncrementalGeneratorInitializationContext:

csharp
// 语法提供者(用于创建管道)
IncrementalGeneratorSyntaxProvider SyntaxProvider { get; }

// 编译提供者
IncrementalValueProvider<Compilation> CompilationProvider { get; }

// 分析器配置选项提供者
IncrementalValueProvider<AnalyzerConfigOptionsProvider> AnalyzerConfigOptionsProvider { get; }

// 附加文本提供者
IncrementalValuesProvider<AdditionalText> AdditionalTextsProvider { get; }

// 元数据引用提供者
IncrementalValuesProvider<MetadataReference> MetadataReferencesProvider { get; }

// 解析选项提供者
IncrementalValueProvider<ParseOptions> ParseOptionsProvider { get; }

// 注册后初始化输出
void RegisterPostInitializationOutput(Action<IncrementalGeneratorPostInitializationContext> callback);

// 注册源输出
void RegisterSourceOutput<TSource>(
    IncrementalValueProvider<TSource> source,
    Action<SourceProductionContext, TSource> action);

void RegisterSourceOutput<TSource>(
    IncrementalValuesProvider<TSource> source,
    Action<SourceProductionContext, TSource> action);

SourceProductionContext:

csharp
// 添加源文件
void AddSource(string hintName, SourceText sourceText);
void AddSource(string hintName, string source);

// 报告诊断
void ReportDiagnostic(Diagnostic diagnostic);

// 取消令牌
CancellationToken CancellationToken { get; }

ForAttributeWithMetadataName (.NET 7+ 高性能 API)

概述

.NET 7 引入的专门用于基于特性的生成器的高性能 API。相比 CreateSyntaxProvider,它针对特性查找进行了优化。

优势:

  • 🚀 更快: 专门为特性查找优化
  • 🎯 更简单: 不需要手动编写语法和语义过滤
  • 📦 内置缓存: 自动处理增量更新

完整示例

csharp
public void Initialize(IncrementalGeneratorInitializationContext context)
{
    // 使用 ForAttributeWithMetadataName 查找标记的类
    var classDeclarations = context.SyntaxProvider
        .ForAttributeWithMetadataName(
            // 特性的完全限定名称
            fullyQualifiedMetadataName: "MyNamespace.MyAttribute",
            
            // 语法谓词:快速过滤(可选,用于进一步优化)
            predicate: static (node, _) => node is ClassDeclarationSyntax,
            
            // 语义转换:提取需要的信息
            transform: static (context, _) => GetClassInfo(context))
        
        // 过滤掉 null 结果
        .Where(static m => m is not null);
    
    // 注册源输出
    context.RegisterSourceOutput(classDeclarations,
        static (spc, classInfo) => GenerateCode(classInfo!, spc));
}

static ClassInfo? GetClassInfo(GeneratorAttributeSyntaxContext context)
{
    // context.TargetNode: 标记的语法节点
    var classDecl = (ClassDeclarationSyntax)context.TargetNode;
    
    // context.TargetSymbol: 标记的符号
    var classSymbol = (INamedTypeSymbol)context.TargetSymbol;
    
    // context.Attributes: 匹配的特性(可能有多个)
    var attribute = context.Attributes[0];
    
    // context.SemanticModel: 语义模型
    var semanticModel = context.SemanticModel;
    
    // 提取信息...
    return new ClassInfo(/*...*/);
}

关键成员

GeneratorAttributeSyntaxContext:

csharp
// 标记的语法节点
SyntaxNode TargetNode { get; }

// 标记的符号
ISymbol TargetSymbol { get; }

// 匹配的特性(可能有多个,如果类上有多个相同特性)
ImmutableArray<AttributeData> Attributes { get; }

// 语义模型
SemanticModel SemanticModel { get; }

API 概览

主要 API 类别

  1. 语法树 API - 处理代码的语法结构

  2. 语义模型 API - 处理代码的语义信息

  3. 编译 API - 管理编译过程

  4. 代码生成 API - 生成新代码

  5. 诊断 API - 报告错误和警告


💡 关键要点

  1. 优先使用增量生成器

    • IIncrementalGenerator 性能远超 ISourceGenerator
    • 支持 IDE 实时反馈
    • 自动缓存和增量更新
  2. 使用 ForAttributeWithMetadataName (.NET 7+)

    • 专门为基于特性的生成器优化
    • 比手动过滤快 5-10 倍
    • 代码更简洁
  3. 两阶段过滤模式

    • 第一阶段:语法过滤(快速)
    • 第二阶段:语义转换(精确)
    • 只对候选节点使用语义模型
  4. 使用轻量级数据模型

    • 使用 record 类型
    • 不要传递 SyntaxNodeISymbol
    • 实现 IEquatable 以支持缓存
  5. 使用静态方法

    • 避免闭包捕获
    • 减少内存分配
    • 提高性能

🔗 相关文档


📚 下一步

学习完 Roslyn API 介绍后,建议继续学习:

  1. 语法树 API - 深入学习语法树操作
  2. 语义模型 API - 掌握语义分析技巧
  3. 常见模式 - 学习实用的代码模式

基于 MIT 许可发布