求助:为Core 2.0代码分析器添加自定义规则的示例
嘿,刚上手基于NuGet的代码分析器是吧?既然已经装了Microsoft.CodeAnalysis.FxCopAnalyzers,那自定义规则其实没你想的那么复杂,我给你结合Core 2.0的场景,一步步写个完整的示例,保证你能快速跑起来~
自定义Core 2.0代码分析规则实现示例
一、先搭好项目结构
首先得创建一个类库项目(.NET Standard 2.0)——因为Core 2.0兼容这个版本,这样你的分析器才能在Core 2.0项目里正常工作。然后安装两个必要的NuGet包:
Microsoft.CodeAnalysis.Analyzers:代码分析器的基础框架Microsoft.CodeAnalysis.CSharp:提供C#语法分析的支持
二、编写自定义分析器规则
我给你写个简单易懂的规则示例:禁止方法名以下划线开头,既能理解核心逻辑,又能快速验证效果。
1. 核心分析器类实现
创建一个继承自DiagnosticAnalyzer的类,这是自定义规则的核心载体:
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 NoUnderscorePrefixMethodAnalyzer : DiagnosticAnalyzer { // 定义诊断的唯一标识、标题、提示信息等 public const string DiagnosticId = "CS0001"; private const string Title = "方法名不能以下划线开头"; private const string MessageFormat = "方法 '{0}' 的名称以下划线开头,不符合编码规范"; private const string Description = "为保持代码风格一致,禁止方法名使用下划线开头"; private const string Category = "Naming"; // 构建诊断规则实例 private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description); // 返回当前分析器支持的所有规则 public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule); // 初始化分析器,注册要监听的语法节点 public override void Initialize(AnalysisContext context) { // 启用并发分析提升性能 context.EnableConcurrentExecution(); // 跳过自动生成的代码(比如Designer文件) context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); // 注册对方法声明节点的分析逻辑 context.RegisterSyntaxNodeAction(AnalyzeMethodDeclaration, SyntaxKind.MethodDeclaration); } // 具体的代码检查逻辑 private void AnalyzeMethodDeclaration(SyntaxNodeAnalysisContext context) { var methodDeclaration = (MethodDeclarationSyntax)context.Node; var methodName = methodDeclaration.Identifier.Text; // 判断方法名是否违反规则 if (methodName.StartsWith("_")) { // 生成诊断信息并报告 var diagnostic = Diagnostic.Create(Rule, methodDeclaration.Identifier.GetLocation(), methodName); context.ReportDiagnostic(diagnostic); } } }
2. 可选:添加自动修复功能
如果想给用户提供一键修复的选项(比如自动去掉下划线),可以写一个CodeFixProvider:
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.Collections.Immutable; using System.Composition; using System.Linq; using System.Threading; using System.Threading.Tasks; [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(NoUnderscorePrefixMethodCodeFixProvider)), Shared] public class NoUnderscorePrefixMethodCodeFixProvider : CodeFixProvider { // 指定当前修复器对应的诊断ID public sealed override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(NoUnderscorePrefixMethodAnalyzer.DiagnosticId); // 批量修复的支持 public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; // 注册修复动作 public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; // 定位到违反规则的方法声明节点 var methodDeclaration = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType<MethodDeclarationSyntax>().First(); // 添加修复选项 context.RegisterCodeFix( CodeAction.Create( title: "移除方法名的下划线前缀", createChangedDocument: c => RemoveUnderscorePrefixAsync(context.Document, methodDeclaration, c), equivalenceKey: nameof(NoUnderscorePrefixMethodCodeFixProvider)), diagnostic); } // 执行修复的具体逻辑 private async Task<Document> RemoveUnderscorePrefixAsync(Document document, MethodDeclarationSyntax methodDeclaration, CancellationToken cancellationToken) { var newMethodName = methodDeclaration.Identifier.Text.TrimStart('_'); var newMethodDeclaration = methodDeclaration.WithIdentifier(SyntaxFactory.Identifier(newMethodName)) .WithLeadingTrivia(methodDeclaration.Identifier.LeadingTrivia) .WithTrailingTrivia(methodDeclaration.Identifier.TrailingTrivia); var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var newRoot = root.ReplaceNode(methodDeclaration, newMethodDeclaration); return document.WithSyntaxRoot(newRoot); } }
三、打包成NuGet包(供Core 2.0项目引用)
要让自定义规则像FxCopAnalyzers一样通过NuGet安装,需要修改类库项目的.csproj文件:
<PropertyGroup> <TargetFramework>netstandard2.0</TargetFramework> <IncludeBuildOutput>false</IncludeBuildOutput> </PropertyGroup> <ItemGroup> <!-- 把编译后的分析器DLL打包到NuGet的指定目录 --> <None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/csharp" /> </ItemGroup>
配置好后右键项目选择「打包」,就能生成对应的.nupkg文件了。
四、在Core 2.0项目中使用
- 把生成的NuGet包添加到本地NuGet源,然后在Core 2.0项目中安装这个包。
- 打开项目的「Analyzer」节点,就能看到你的自定义规则。当代码中出现以下划线开头的方法时,会触发警告,还能点击修复按钮自动移除下划线。
小提示
- Core 2.0项目一定要确保分析器基于.NET Standard 2.0,否则会有兼容性问题。
- 如果需要更复杂的规则(比如分析方法的访问权限、返回类型等语义信息),可以用
context.RegisterSymbolAction来分析IMethodSymbol,能获取更多代码上下文。
内容的提问来源于stack exchange,提问作者Agrawal Shraddha




