Skip to content

诊断 API 完整参考

本文档是诊断 API 的索引和导航页面,帮助你快速找到需要的内容。

📚 文档信息

  • 难度级别: 中级到高级
  • 预计阅读时间: 10 分钟(索引)
  • 前置知识:
    • C# 基础语法
    • Roslyn 基本概念
    • 源生成器基础

🎯 学习目标

通过本系列文档,你将学会:

  • ✅ 创建和配置诊断描述符
  • ✅ 报告诊断到 IDE
  • ✅ 选择合适的严重级别
  • ✅ 实现完整的诊断分析器
  • ✅ 精确指定诊断位置
  • ✅ 格式化诊断消息

📖 什么是诊断 API?

诊断 API 是 Roslyn 提供的一套工具,用于创建自定义的代码分析器。通过诊断 API,你可以:

  • 检测代码问题:发现命名不规范、性能问题、潜在错误等
  • 提供实时反馈:在 IDE 中实时显示波浪线和错误信息
  • 引导最佳实践:帮助团队遵循编码规范
  • 自动化代码审查:减少人工审查的工作量

典型应用场景

  • 强制执行团队的命名规范
  • 检测常见的性能问题(如循环中创建对象)
  • 发现潜在的空引用错误
  • 确保 API 的正确使用

🚀 快速开始

在深入细节之前,让我们看一个完整的例子:

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

[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class SimpleClassNameAnalyzer : DiagnosticAnalyzer
{
    // 步骤 1:定义诊断规则
    private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(
        id: "DEMO001",
        title: "类名应该以大写字母开头",
        messageFormat: "类名 '{0}' 应该以大写字母开头",
        category: "Naming",
        defaultSeverity: DiagnosticSeverity.Warning,
        isEnabledByDefault: true);
    
    // 步骤 2:声明支持的诊断
    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
        ImmutableArray.Create(Rule);
    
    // 步骤 3:初始化分析器
    public override void Initialize(AnalysisContext context)
    {
        context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
        context.EnableConcurrentExecution();
        context.RegisterSyntaxNodeAction(AnalyzeClass, SyntaxKind.ClassDeclaration);
    }
    
    // 步骤 4:实现分析逻辑
    private void AnalyzeClass(SyntaxNodeAnalysisContext context)
    {
        var classDeclaration = (ClassDeclarationSyntax)context.Node;
        var className = classDeclaration.Identifier.Text;
        
        if (!char.IsUpper(className[0]))
        {
            var diagnostic = Diagnostic.Create(
                Rule,
                classDeclaration.Identifier.GetLocation(),
                className);
            
            context.ReportDiagnostic(diagnostic);
        }
    }
}

📑 文档列表

本系列文档包含以下内容:

文档描述难度阅读时间
DiagnosticDescriptor 详解诊断描述符的创建和配置中级20 分钟
Diagnostic 报告如何创建和报告诊断中级15 分钟
严重级别Error、Warning、Info、Hidden 的选择指南初级10 分钟
DiagnosticAnalyzer 实现完整的诊断分析器实现高级30 分钟
诊断位置和范围精确指定诊断的位置和范围中级15 分钟
消息格式化诊断消息的格式化和本地化初级10 分钟
最佳实践使用诊断 API 的最佳实践中级15 分钟

🗺️ 学习路径

初学者路径

如果你是第一次使用诊断 API,建议按以下顺序学习:

  1. 严重级别 - 了解不同级别的含义
  2. DiagnosticDescriptor 详解 - 学习如何定义诊断规则
  3. Diagnostic 报告 - 学习如何报告诊断
  4. DiagnosticAnalyzer 实现 - 实现完整的分析器
  5. 最佳实践 - 学习最佳实践

进阶路径

如果你已经有一些经验,可以直接查阅:

🔑 核心概念速查

DiagnosticDescriptor(诊断描述符)

定义诊断的元数据:

csharp
var rule = new DiagnosticDescriptor(
    id: "MYLIB001",                    // 唯一标识符
    title: "类名应该使用 PascalCase",   // 简短标题
    messageFormat: "类名 '{0}' 应该使用 PascalCase 命名",  // 消息格式
    category: "Naming",                // 类别
    defaultSeverity: DiagnosticSeverity.Warning,  // 严重级别
    isEnabledByDefault: true);         // 是否默认启用

Diagnostic(诊断)

表示一个具体的诊断实例:

csharp
var diagnostic = Diagnostic.Create(
    descriptor: rule,                  // 诊断描述符
    location: node.GetLocation(),      // 位置
    messageArgs: className);           // 消息参数

DiagnosticAnalyzer(诊断分析器)

实现诊断逻辑的基类:

csharp
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class MyAnalyzer : DiagnosticAnalyzer
{
    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; }
    public override void Initialize(AnalysisContext context) { }
}

严重级别

级别显示编译用途
Error红色波浪线阻止必须修复的问题
Warning绿色波浪线不阻止应该修复的问题
Info灰色点状线不阻止建议性的改进
Hidden不显示不阻止代码修复触发

🎨 诊断报告流程

💡 常见使用场景

场景 1:命名规则检查

检查类名、方法名等是否符合命名约定。

相关文档

场景 2:性能问题检测

检测循环中创建对象、字符串拼接等性能问题。

相关文档

场景 3:安全检查

检测可能的空引用、不安全的类型转换等。

相关文档

❓ 常见问题

我应该使用哪种严重级别?

  • Error:违反语言规则或会导致运行时错误
  • Warning:不符合最佳实践或可能导致问题
  • Info:建议性的改进
  • Hidden:只用于代码修复触发

详见:严重级别

如何提高分析器性能?

  1. 启用并发执行
  2. 使用合适的分析动作
  3. 快速检查后再详细分析
  4. 避免耗时操作

详见:最佳实践

如何精确指定诊断位置?

使用 Token 的位置而不是整个节点的位置:

csharp
// ✅ 正确:只标记标识符
classDeclaration.Identifier.GetLocation()

// ❌ 错误:标记整个类声明
classDeclaration.GetLocation()

详见:诊断位置和范围

🔗 相关文档

API 参考

学习指南

📝 下一步

选择一个文档开始学习:


返回: API 参考首页 | 下一篇: DiagnosticDescriptor 详解

基于 MIT 许可发布