C# Roslyn API: 在每个节点成员之间插入 Instructions/Methods

C# Roslyn API: Insert Instructions/Methods between each nodes members

我刚刚进入一个个人项目,我希望能够使用 Roslyn API 在 class 成员之间插入指令/方法(So 方法/指令)

我目前能够像这里一样检索不同的子节点:命名空间> Class> 字段/方法

但我想知道如何在字段/方法之间插入代码而不是替换代码。

(以下图红线位置为例)

编辑:经过更多研究,我发现我可以使用 InsertTokensBeforeInsertNodesBeforeInsertTriviaBefore,但我不明白如何解析我的函数(实际上在 text/string格式)到需要的参数。

您可以使用 Microsoft.CodeAnalysis.CSharp.SyntaxFactory to build a Microsoft.CodeAnalysis.SyntaxNode.

要获取创建新语法树所需的语法工厂代码,请查看精彩的 RoslynQuoter。 在那里,您可以通过语法工厂 API:

放入要构建的 C# 程序
public class RoslynClass
{
    public static int RoslynMethod(int left, int right)
    {
        return left + right;
    }
}

根据您的喜好检查所有选项,然后 Get Roslyn API 调用以生成此代码!,您可以(部分)在生产代码中使用它。

这里我列出了一个源代码重构的例子,它插入方法public static int RoslynMethod(int left, int right) before/after或者字段 方法 :

using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editing;

namespace RoslynTool
{
    [ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = nameof(MethodInserter))]
    [Shared]
    internal sealed class MethodInserter : CodeRefactoringProvider
    {
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            SyntaxNode root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
            SyntaxNode node = root.FindNode(context.Span);

            if (node is FieldDeclarationSyntax or MethodDeclarationSyntax)
            {
                SyntaxNode newNode = CreateMethodNode();

                context.RegisterRefactoring(CodeAction.Create("Insert method before", ct => InsertBeforeAsync(context.Document, node, newNode, ct)));
                context.RegisterRefactoring(CodeAction.Create("Insert method after", ct => InsertAfterAsync(context.Document, node, newNode, ct)));
            }
        }

        private static MemberDeclarationSyntax CreateMethodNode()
        {
            return SyntaxFactory.MethodDeclaration(
                SyntaxFactory.PredefinedType(
                    SyntaxFactory.Token(SyntaxKind.IntKeyword)),
                SyntaxFactory.Identifier("RoslynMethod"))
                .WithModifiers(
                    SyntaxFactory.TokenList(new[] {
                        SyntaxFactory.Token(SyntaxKind.PublicKeyword),
                        SyntaxFactory.Token(SyntaxKind.StaticKeyword)}))
                .WithParameterList(
                    SyntaxFactory.ParameterList(
                        SyntaxFactory.SeparatedList<ParameterSyntax>(new SyntaxNodeOrToken[] {
                            SyntaxFactory.Parameter(
                                SyntaxFactory.Identifier("left"))
                            .WithType(
                                SyntaxFactory.PredefinedType(
                                    SyntaxFactory.Token(SyntaxKind.IntKeyword))),
                            SyntaxFactory.Token(SyntaxKind.CommaToken),
                            SyntaxFactory.Parameter(
                                SyntaxFactory.Identifier("right"))
                            .WithType(
                                SyntaxFactory.PredefinedType(
                                    SyntaxFactory.Token(SyntaxKind.IntKeyword)))})))
                .WithBody(
                    SyntaxFactory.Block(
                        SyntaxFactory.SingletonList<StatementSyntax>(
                            SyntaxFactory.ReturnStatement(
                                SyntaxFactory.BinaryExpression(
                                    SyntaxKind.AddExpression,
                                    SyntaxFactory.IdentifierName("left"),
                                    SyntaxFactory.IdentifierName("right"))))));
        }

        private static async Task<Document> InsertBeforeAsync(Document document, SyntaxNode location, SyntaxNode newNode, CancellationToken cancellationToken)
        {
            DocumentEditor documentEditor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false);
            documentEditor.InsertBefore(location, newNode);

            return documentEditor.GetChangedDocument();
        }

        private static async Task<Document> InsertAfterAsync(Document document, SyntaxNode location, SyntaxNode newNode, CancellationToken cancellationToken)
        {
            DocumentEditor documentEditor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false);
            documentEditor.InsertAfter(location, newNode);

            return documentEditor.GetChangedDocument();
        }
    }
}

或者,SyntaxFactory could be used to create a new SyntaxNodeparse 方法,但在该示例中我无法正确获得 whitespaces/trivia:

namespace RoslynTool
{
    internal sealed class MethodInserter : CodeRefactoringProvider
    {
        private static MemberDeclarationSyntax CreateMethodNode()
        {
            return SyntaxFactory.ParseMemberDeclaration(@"
        public static int RoslynMethod(int left, int right)
        {
            return left + right;
        }
");
        }
    }
}

希望我正确理解了你的问题。