在现代C#开发中,保持代码的一致性、可读性和安全性至关重要。借助Roslyn分析器,开发者可以轻松创建自定义代码规则,在编译时自动检测不符合规范的代码,并提供修复建议。本文将手把手教你从零开始构建一个简单的Roslyn分析器,即使你是初学者也能轻松上手。
Roslyn 是 .NET 编译器平台,它不仅负责编译 C# 和 VB.NET 代码,还提供了丰富的 API,允许开发者对源代码进行分析和修改。Roslyn分析器就是基于这些 API 构建的工具,用于在开发过程中实时检查代码质量。
通过编写自定义分析器,你可以:
你需要安装以下工具:
打开 Visual Studio,选择“创建新项目”,搜索“Analyzer”,选择“Analyzer with Code Fix (.NET Standard)”模板(注意:该模板可能需要安装“.NET Compiler Platform SDK”扩展)。
项目创建后,你会看到三个关键文件:
XXXAnalyzer.cs:定义分析逻辑XXXCodeFixProvider.cs:提供自动修复方案XXXDiagnosticAnalyzer.cs:注册诊断规则我们来实现一个简单但实用的规则:禁止在类中使用 public 字段,必须使用属性封装。
打开 XXXAnalyzer.cs 文件,替换为以下代码:
using Microsoft.CodeAnalysis;using Microsoft.CodeAnalysis.CSharp;using Microsoft.CodeAnalysis.CSharp.Syntax;using Microsoft.CodeAnalysis.Diagnostics;using System.Collections.Immutable;namespace MyCustomAnalyzer{ [DiagnosticAnalyzer(LanguageNames.CSharp)] public class NoPublicFieldsAnalyzer : DiagnosticAnalyzer { public const string DiagnosticId = "NoPublicFields"; private static readonly LocalizableString Title = "Avoid public fields"; private static readonly LocalizableString MessageFormat = "Public field '{0}' should be converted to a property."; private static readonly LocalizableString Description = "Public fields break encapsulation. Use properties instead."; private const string Category = "Design"; private static readonly DiagnosticDescriptor Rule = new( 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.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.EnableConcurrentExecution(); context.RegisterSyntaxNodeAction(AnalyzeFieldDeclaration, SyntaxKind.FieldDeclaration); } private static void AnalyzeFieldDeclaration(SyntaxNodeAnalysisContext context) { var fieldDeclaration = (FieldDeclarationSyntax)context.Node; // 检查字段是否包含 public 修饰符 if (fieldDeclaration.Modifiers.Any(SyntaxKind.PublicKeyword)) { foreach (var variable in fieldDeclaration.Declaration.Variables) { var diagnostic = Diagnostic.Create( Rule, variable.GetLocation(), variable.Identifier.Text); context.ReportDiagnostic(diagnostic); } } } }} 为了让开发者能一键修复问题,我们还需实现 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;namespace MyCustomAnalyzer{ [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(NoPublicFieldsCodeFixProvider))] [Shared] public class NoPublicFieldsCodeFixProvider : CodeFixProvider { public sealed override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(NoPublicFieldsAnalyzer.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 fieldIdentifier = root.FindToken(diagnosticSpan.Start).Parent .AncestorsAndSelf().OfType<VariableDeclaratorSyntax>().First(); context.RegisterCodeFix( CodeAction.Create( title: "Convert to auto-property", createChangedDocument: c => ConvertToProperty(context.Document, fieldIdentifier, c), equivalenceKey: "ConvertToProperty"), diagnostic); } private async Task<Document> ConvertToProperty( Document document, VariableDeclaratorSyntax field, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken); var fieldDecl = field.AncestorsOfType<FieldDeclarationSyntax>().First(); // 创建属性语法 var property = SyntaxFactory.PropertyDeclaration( fieldDecl.Declaration.Type, field.Identifier) .WithModifiers(fieldDecl.Modifiers) .WithAccessorList(SyntaxFactory.AccessorList( SyntaxFactory.List(new[] { SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)), SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)) }))); var newRoot = root.ReplaceNode(fieldDecl, property); return document.WithSyntaxRoot(newRoot); } }} 按 F5 运行项目,Visual Studio 会启动一个新的实验实例。在新窗口中创建一个控制台项目,输入以下代码:
public class Person{ public string Name; // ← 这里会出现警告!} 你会看到 Name 字段下方出现波浪线,并提示“Public field 'Name' should be converted to a property.”。点击灯泡图标,即可应用自动修复,将其转换为属性。
完成开发后,你可以将分析器打包为 NuGet 包,供团队其他成员使用。只需在项目文件中添加:
<PackageReference Include="MyCustomAnalyzer" Version="1.0.0" PrivateAssets="all" /> 这样,所有引用该项目的代码都会自动应用你的C#代码分析规则。
通过 Roslyn 分析器,你可以将团队的最佳实践固化为代码规则,大幅提升代码质量和维护效率。无论是实施安全策略、性能优化还是风格统一,.NET静态分析都是不可或缺的利器。现在就动手创建属于你自己的分析器吧!
关键词回顾:Roslyn分析器、C#代码分析、自定义代码规则、.NET静态分析
本文由主机测评网于2025-12-05发表在主机测评网_免费VPS_免费云服务器_免费独立服务器,如有疑问,请联系我们。
本文链接:https://www.vpshk.cn/2025123375.html