Building a SyntaxTree from the ground up

a 夏天 提交于 2019-11-28 17:16:00
Matt Warren

This will build up your entire compilation unit tree in one expression.

var cu = SyntaxFactory.CompilationUnit()
            .AddMembers(
                SyntaxFactory.NamespaceDeclaration(Syntax.IdentifierName("ACO"))
                        .AddMembers(
                        SyntaxFactory.ClassDeclaration("MainForm")
                            .AddBaseListTypes(SyntaxFactory.ParseTypeName("System.Windows.Forms.Form"))
                            .WithModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword))
                            .AddMembers(
                                Syntax.PropertyDeclaration(SyntaxFactory.ParseTypeName("System.Windows.Forms.Timer"), "Ticker")
                                        .AddAccessorListAccessors(
                                        SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)),
                                        SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))),
                                SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("void"), "Main")
                                        .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword))
                                        .AddAttributes(SyntaxFactory.AttributeDeclaration().AddAttributes(SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("STAThread"))))
                                        .WithBody(SyntaxFactory.Block())
                                )
                        )
                );

Of course, you don't have to do it as a single expression. I could have used separate local variables to collect the pieces I wanted and then added them in the construction of the containing syntax piece.

Believe it or not, I have written a tool called Roslyn Code Quoter especially to answer this question.

http://roslynquoter.azurewebsites.net

The tool can take any C# program and automatically generate a snippet of code like Matt has written above. Since it also generates everything perfectly including all the whitespace, the code can get rather unwieldy. But you can exclude parts that generate trivia, and then just call NormalizeWhitespace() on the resulting node, it will automatically insert the trivia so that the code is correctly formatted.

For the sake of completeness I'm posting the code in all its gory detail, so that you can see how to construct whitespace and all those little details.

CompilationUnit().WithMembers(
SingletonList<MemberDeclarationSyntax>(
    NamespaceDeclaration(
        IdentifierName("ACO"))
    .WithMembers(
        SingletonList<MemberDeclarationSyntax>(
            ClassDeclaration("MainForm")
            .WithModifiers(
                TokenList(
                    Token(SyntaxKind.PublicKeyword)))
            .WithBaseList(
                BaseList(
                    SingletonSeparatedList<BaseTypeSyntax>(
                        SimpleBaseType(
                            QualifiedName(
                                QualifiedName(
                                    QualifiedName(
                                        IdentifierName("System"),
                                        IdentifierName("Windows")),
                                    IdentifierName("Forms")),
                                IdentifierName("Form"))))))
            .WithMembers(
                List<MemberDeclarationSyntax>(
                    new MemberDeclarationSyntax[]{
                        PropertyDeclaration(
                            QualifiedName(
                                QualifiedName(
                                    QualifiedName(
                                        IdentifierName("System"),
                                        IdentifierName("Windows")),
                                    IdentifierName("Forms")),
                                IdentifierName("Timer")),
                            Identifier("Ticker"))
                        .WithModifiers(
                            TokenList(
                                Token(SyntaxKind.PublicKeyword)))
                        .WithAccessorList(
                            AccessorList(
                                List<AccessorDeclarationSyntax>(
                                    new AccessorDeclarationSyntax[]{
                                        AccessorDeclaration(
                                            SyntaxKind.GetAccessorDeclaration)
                                        .WithSemicolonToken(
                                            Token(SyntaxKind.SemicolonToken)),
                                        AccessorDeclaration(
                                            SyntaxKind.SetAccessorDeclaration)
                                        .WithSemicolonToken(
                                            Token(SyntaxKind.SemicolonToken))}))),
                        MethodDeclaration(
                            PredefinedType(
                                Token(SyntaxKind.VoidKeyword)),
                            Identifier("Main"))
                        .WithAttributeLists(
                            SingletonList<AttributeListSyntax>(
                                AttributeList(
                                    SingletonSeparatedList<AttributeSyntax>(
                                        Attribute(
                                            IdentifierName("STAThread"))))))
                        .WithModifiers(
                            TokenList(
                                Token(SyntaxKind.PublicKeyword)))
                        .WithBody(
                            Block())}))))))
.NormalizeWhitespace()
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!