C# Roslyn API: 在每个节点成员之间插入 Instructions/Methods
C# Roslyn API: Insert Instructions/Methods between each nodes members
我刚刚进入一个个人项目,我希望能够使用 Roslyn API 在 class 成员之间插入指令/方法(So 方法/指令)
我目前能够像这里一样检索不同的子节点:命名空间> Class> 字段/方法
但我想知道如何在字段/方法之间插入代码而不是替换代码。
(以下图红线位置为例)
编辑:经过更多研究,我发现我可以使用 InsertTokensBefore
、InsertNodesBefore
或 InsertTriviaBefore
,但我不明白如何解析我的函数(实际上在 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 SyntaxNode 的 parse 方法,但在该示例中我无法正确获得 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;
}
");
}
}
}
希望我正确理解了你的问题。
我刚刚进入一个个人项目,我希望能够使用 Roslyn API 在 class 成员之间插入指令/方法(So 方法/指令)
我目前能够像这里一样检索不同的子节点:命名空间> Class> 字段/方法
但我想知道如何在字段/方法之间插入代码而不是替换代码。
(以下图红线位置为例)
编辑:经过更多研究,我发现我可以使用 InsertTokensBefore
、InsertNodesBefore
或 InsertTriviaBefore
,但我不明白如何解析我的函数(实际上在 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 SyntaxNode 的 parse 方法,但在该示例中我无法正确获得 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;
}
");
}
}
}
希望我正确理解了你的问题。