c# - 使用 Roslyn 将类(class)成员添加到特定位置?

标签 c# roslyn

我正在使用 ClassDeclarationSyntax.AddMembers() 向类中添加方法。该方法出现在类中,但我想知道如何将方法添加到特定位置。截至目前,它们已添加到类末尾的 #if 指令中。

罗斯林版本:4.4.0

运行代码:

var tree = CSharpSyntaxTree.ParseText(@"
namespace Test
{
public class A
{
#if !SILVERLIGHT
public int someField;
#endif
}
}");

var classNode = tree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>().First();

var previousWhiteSpacesToken =
    SyntaxFactory.Token(SyntaxTriviaList.Empty, SyntaxKind.None, SyntaxTriviaList.Empty);

var method = SyntaxFactory.MethodDeclaration( //
        SyntaxFactory.PredefinedType( //
            SyntaxFactory.Token(SyntaxKind.IntKeyword)), "CalculateSize") //
    .WithModifiers(SyntaxTokenList.Create(previousWhiteSpacesToken)
        .Add(SyntaxFactory.Token(SyntaxKind.PublicKeyword))) //
    .WithBody(SyntaxFactory.Block()).NormalizeWhitespace();

var newClassNode = classNode.AddMembers(method).NormalizeWhitespace();
Console.WriteLine(newClassNode.ToString());

会得到这样的结果:

public class A
{
#if !SILVERLIGHT
    public int someField;
    public int CalculateSize()
    {
    }
#endif
}

我知道有办法做到这一点,但是这个结果只能保证正确性:

public class A
{
    public int CalculateSize()
    {
    }
#if !SILVERLIGHT
    public int someField;
#endif
}

我期望这样的结果:

public class A
{
#if !SILVERLIGHT
    public int someField;
#endif
    public int CalculateSize()
    {
    }  
}

最佳答案

这里的问题是 #endif 是关闭类声明的 的主要琐事。因此,当您刚刚添加一个成员时,#endif 仍然是 } 的主要琐事。

您需要做的是将 的主要琐事移动到您要添加的新方法的主要琐事。

这是您的代码的修改版本:

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

var tree = CSharpSyntaxTree.ParseText(@"
namespace Test
{
public class A
{
#if !SILVERLIGHT
public int someField;
#endif
}
}");

var classNode = tree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>().First();

var previousWhiteSpacesToken =
    SyntaxFactory.Token(SyntaxTriviaList.Empty, SyntaxKind.None, SyntaxTriviaList.Empty);

var method = SyntaxFactory.MethodDeclaration( //
        SyntaxFactory.PredefinedType( //
            SyntaxFactory.Token(SyntaxKind.IntKeyword)), "CalculateSize") //
    .WithModifiers(SyntaxTokenList.Create(previousWhiteSpacesToken)
        .Add(SyntaxFactory.Token(SyntaxKind.PublicKeyword))) //
    .WithBody(SyntaxFactory.Block())
    .WithLeadingTrivia(classNode.CloseBraceToken.LeadingTrivia).NormalizeWhitespace(); // copy '}' leading trivia to the new method.

// remove leading trivia from '}', they are moved previously to the new method.
var newClassNode = classNode.WithCloseBraceToken(classNode.CloseBraceToken.WithLeadingTrivia()).AddMembers(method).NormalizeWhitespace();
Console.WriteLine(newClassNode.ToString());

这将打印以下内容(完全符合您的期望):

public class A
{
#if !SILVERLIGHT
    public int someField;
#endif
    public int CalculateSize()
    {
    }
}

关于c# - 使用 Roslyn 将类(class)成员添加到特定位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74751968/

相关文章:

c# - Roslyn - 在不保留优先级的 SyntaxNode 上调用 ToString

c# - 如何使用 Roslyn 否定 ExpressionSyntax

c# - 在 CMake 中使用多个代码生成器

c# - 用于 Salesforce 出站消息传递的契约(Contract)优先 WCF

c# - 通用类型的集合

c# - Roslyn 功能/模式分支 (C# 7) - 如何启用实验性语言功能

c# - 从 C# 调用 JavaScript 时出现错误 UnathorizedException

c# - 使用选择器的表达式树条件转换

c# - 无法从源代码在 Roslyn 中创建编译

c# - Roslyn 和 .NET 运行时版本