Reputation: 33
I'm using ClassDeclarationSyntax.AddMembers()
to add methods to the class. The method appears in the class, but I would like to know how to add the method to a specific place. As of now, they are added to the #if
directive at the end of the class.
Roslyn version: 4.4.0
Running the code:
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());
This result will be obtained:
public class A
{
#if !SILVERLIGHT
public int someField;
public int CalculateSize()
{
}
#endif
}
I know that there is a way to do this, but this result can only guarantee correctness:
public class A
{
public int CalculateSize()
{
}
#if !SILVERLIGHT
public int someField;
#endif
}
I expected this result:
public class A
{
#if !SILVERLIGHT
public int someField;
#endif
public int CalculateSize()
{
}
}
Upvotes: 3
Views: 247
Reputation: 4986
The problem here is that #endif
is the leading trivia of }
that closes the class declaration. So, when you just add a member, the #endif
remains as the leading trivia of }
.
What you need to do is to move the leading trivia of }
to be the leading trivia of the new method you are adding.
Here is the modified version of your code:
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());
This prints the following (exactly your expectation):
public class A
{
#if !SILVERLIGHT
public int someField;
#endif
public int CalculateSize()
{
}
}
Upvotes: 2