诊断 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,建议按以下顺序学习:
- 严重级别 - 了解不同级别的含义
- DiagnosticDescriptor 详解 - 学习如何定义诊断规则
- Diagnostic 报告 - 学习如何报告诊断
- DiagnosticAnalyzer 实现 - 实现完整的分析器
- 最佳实践 - 学习最佳实践
进阶路径
如果你已经有一些经验,可以直接查阅:
🔑 核心概念速查
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:只用于代码修复触发
详见:严重级别
如何提高分析器性能?
- 启用并发执行
- 使用合适的分析动作
- 快速检查后再详细分析
- 避免耗时操作
详见:最佳实践
如何精确指定诊断位置?
使用 Token 的位置而不是整个节点的位置:
csharp
// ✅ 正确:只标记标识符
classDeclaration.Identifier.GetLocation()
// ❌ 错误:标记整个类声明
classDeclaration.GetLocation()详见:诊断位置和范围
🔗 相关文档
API 参考
学习指南
📝 下一步
选择一个文档开始学习:
- 初学者:从 严重级别 开始
- 有经验:直接查看 DiagnosticAnalyzer 实现
- 优化现有代码:查看 最佳实践
返回: API 参考首页 | 下一篇: DiagnosticDescriptor 详解