首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

使用 `Roslyn` 分析器和修复器 对异步方法规范化返回Async结尾

编程知识
2024年09月13日 16:27

之前写过一篇使用修复器帮助添加头部注释文本的功能,今天使用Roslyn的代码修复器对异步返回方法规范化的功能

实现分析器

首先需要实现分析器,使用RegisterSyntaxNodeAction,分析所有SyntaxKind.MethodDeclaration的语法类型,

[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class AsyncMethodNameAnalyzer : DiagnosticAnalyzer
{
    public const string DiagnosticId = "GEN051";
    private static readonly LocalizableString Title = "将异步方法名改为以Async结尾";
    private static readonly LocalizableString MessageFormat = "将异步方法名改为以Async结尾";
    private static readonly LocalizableString Description = "将异步方法名改为以Async结尾.";
    private const string Category = "Documentation";

    private static readonly DiagnosticDescriptor Rule = new(
    DiagnosticId, Title, MessageFormat, Category,
    DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description);

    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => [Rule];


    public override void Initialize(AnalysisContext context)
    {
        if (context is null)
            return;
        context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
        context.EnableConcurrentExecution();
        context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.MethodDeclaration);
    }

    // 异步方法名称应该以Async结尾
    private const string AsyncSuffix = "Async";

    private static void AnalyzeNode(SyntaxNodeAnalysisContext context)
    {
        var methodDeclaration = (MethodDeclarationSyntax)context.Node;

        //如果方法包含async修饰的情况
        if (methodDeclaration.Modifiers.Any(SyntaxKind.AsyncKeyword))
        {
            if (!methodDeclaration.Identifier.Text.EndsWith(AsyncSuffix, StringComparison.OrdinalIgnoreCase))
            {
                var diagnostic = Diagnostic.Create(Rule, methodDeclaration.Identifier.GetLocation(), methodDeclaration.Identifier.Text);
                context.ReportDiagnostic(diagnostic);
            }
        }

        var returnType = methodDeclaration.ReturnType;

        //如果返回类型为Task或者Task<T>,或者ValueTask<T>,ValueTask 则方法名应该以Async结尾
        // 判断返回类型是否为 Task 或 ValueTask
        if (returnType is IdentifierNameSyntax identifierName)
        {
            if (identifierName.Identifier.Text == "Task" || identifierName.Identifier.Text == "ValueTask")
            {
                if (!methodDeclaration.Identifier.Text.EndsWith(AsyncSuffix, StringComparison.OrdinalIgnoreCase))
                {
                    var diagnostic = Diagnostic.Create(Rule, methodDeclaration.Identifier.GetLocation(), methodDeclaration.Identifier.Text);
                    context.ReportDiagnostic(diagnostic);
                }
            }
        }
        else if (returnType is GenericNameSyntax genericName && (genericName.Identifier.Text == "Task" || genericName.Identifier.Text == "ValueTask"))
        {
            if (!methodDeclaration.Identifier.Text.EndsWith(AsyncSuffix, StringComparison.OrdinalIgnoreCase))
            {
                var diagnostic = Diagnostic.Create(Rule, methodDeclaration.Identifier.GetLocation(), methodDeclaration.Identifier.Text);
                context.ReportDiagnostic(diagnostic);
            }
        }
    }
}

Initialize 方法中,注册了一个语法节点操作来处理 MethodDeclarationSyntax 节点,主要是考虑方法是否async关键字标注,或者返回的类型是否是Task或者ValueTask,如果这些条件满足则判断方法名称MethodDeclaration.Identifier是否为Async结尾.如果存在这样的问题 那么创建一个诊断并报告。

实现修复器

[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AsyncMethodNameCodeFixProvider))]
[Shared]
internal class AsyncMethodNameCodeFixProvider : CodeFixProvider
{
    public override ImmutableArray<string> FixableDiagnosticIds => [AsyncMethodNameAnalyzer.DiagnosticId];

    public sealed override FixAllProvider GetFixAllProvider() =>
        WellKnownFixAllProviders.BatchFixer;

    private const string Title = "将异步方法名改为以Async结尾";


    public override Task RegisterCodeFixesAsync(CodeFixContext context)
    {
        var diagnostic = context.Diagnostics[0];
        var diagnosticSpan = diagnostic.Location.SourceSpan;

        context.RegisterCodeFix(
            CodeAction.Create(
                title: Title,
                createChangedDocument:
                c =>
                FixDocumentAsync(context.Document, diagnostic, c),
                equivalenceKey: Title),
            diagnostic);

        return Task.CompletedTask;

    }

    private const string AsyncSuffix = "Async";

    private static async Task<Document> FixDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken c)
    {
        var root = await document.GetSyntaxRootAsync(c).ConfigureAwait(false);

        if (root == null)
            return document;

        var node = root.FindNode(diagnostic.Location.SourceSpan);
        var methodDeclaration = (MethodDeclarationSyntax)node;
        var newName = $"{methodDeclaration.Identifier.Text}{AsyncSuffix}";
        var newRoot = root.ReplaceNode(methodDeclaration, methodDeclaration.WithIdentifier(SyntaxFactory.Identifier(newName)));
        return document.WithSyntaxRoot(newRoot);
    }
}

修复器的实现就更加简单了,我们通过诊断信息和Document就可以定位到有问题的方法本身,然后使用WithIdentifierSyntaxFactory.Identifier将方法名称修正为正确的值 并返回修复的Document即可!

预览效果

最后我们看一下效果

编译时返回的警告信息
image
编辑文档是产生的提示信息
image
点击提示即可修复代码问题
image

最后

其实这个属于代码习惯或者代码风格的问题,个人是比较推荐异步方法还是加上后缀的,毕竟有了这个规范我们一看方法就能知道这是一个异步方法 😃

最后你可以使用我发布的nuget包体验:

dotnet add package Biwen.AutoClassGen

源代码我发布到了GitHub,欢迎star! https://github.com/vipwan/Biwen.AutoClassGen

From:https://www.cnblogs.com/vipwan/p/18412585
本文地址: http://www.shuzixingkong.net/article/1988
0评论
提交 加载更多评论
其他文章 吊打面试官!从多维度理解架构
大家好,我是汤师爷~ 在工作当中,我们经常会听到以下说法: 产品负责人说,现在的业务架构太复杂,需要仔细梳理下。 技术领导说,这个项目很复杂,需要做下系统架构方案评审。 研发经理说,这次秒杀活动访问量非常大,需要用到高并发架构方案。 一线研发说,互联网大厂都会用到微服务架构,我要学学微服务架构设计。
吊打面试官!从多维度理解架构 吊打面试官!从多维度理解架构 吊打面试官!从多维度理解架构
Python网页应用开发神器Dash 2.18.1稳定版本来啦
本文示例代码已上传至我的Github仓库:https://github.com/CNFeffery/dash-master Gitee同步仓库地址:https://gitee.com/cnfeffery/dash-master 大家好我是费老师,上周Dash发布了2.18.0新版本,并于今天发布了可
Python网页应用开发神器Dash 2.18.1稳定版本来啦 Python网页应用开发神器Dash 2.18.1稳定版本来啦 Python网页应用开发神器Dash 2.18.1稳定版本来啦
架构师备考的一些思考(四)
前言 对于数学,我们之前学的是对的,但不是真的,所以我们没有数学思维。 对于计算机,我们学校教的是对的,但不是真的,所以仅仅从学校学习知识的应届毕业生,不论985,211,本科,专科都一样,都是一张白纸,啥也不会。 案例分析 案例分析是5选3,第一题必答。 问题一的类型 架构风格对比 问题二的类型
架构师备考的一些思考(四)
Linux下Shell脚本实现统一管理服务启停重启
公司今年开始了大批量的裁员,人心惶惶,所以强迫自己学习点新知识,刚好领导给找了个事情,让写个脚本实现一键启停Linux服务器上的服务,于是开始研究这个怎么搞。 最开始的时候,有点想当然了,觉得一键启停不就是写个菜单,调用一下服务启动停止的命令就可以实现,但是在写的过程中,发现全是坑,搞的心态都崩了,
Go runtime 调度器精讲(四):运行 main goroutine
原创文章,欢迎转载,转载请注明出处,谢谢。 0. 前言 皇天不负有心人,终于我们到了运行 main goroutine 环节了。让我们走起来,看看一个 goroutine 到底是怎么运行的。 1. 运行 goroutine 稍微回顾下前面的内容,第一讲 Go 程序初始化,介绍了 Go 程序是怎么进入
Go runtime 调度器精讲(四):运行 main goroutine
chainLink vrf实验
title: chainLink vrf实验 author: ivhu date: 2024-09-13 14:00:42 categories: - 区块链 - 二层 tags: - solidity - ch - vrf description: 博客园我这个主题对sol的高亮不太行,可以去我g
chainLink vrf实验 chainLink vrf实验 chainLink vrf实验
数据结构之美-深入理解树形结构
树形结构是一种广泛应用的非线性数据结构,它在计算机科学和日常生活中都有广泛的应用。比如文件系统,邮件系统,编译器语法树,决策树,网络通信,甚至机器学习当中,都有树形数据结构的影子。本文旨在梳理日常用到的各类树形结构以及其优点和劣势,让渎者对树形结构有一个深入的认知和了解。
数据结构之美-深入理解树形结构 数据结构之美-深入理解树形结构 数据结构之美-深入理解树形结构
Qml 实现水波进度动画条
最近看到一个非常有趣的动画效果:**水波进度动画。** 学习了一下实现思路,觉得很有意思。 不过原版是 `HTML + CSS`,我这里用的是 `Qml`,有一些小技巧,分享给大家~
Qml 实现水波进度动画条 Qml 实现水波进度动画条 Qml 实现水波进度动画条