【问题标题】:Building a SyntaxTree from the ground up从头开始构建语法树
【发布时间】:2017-06-24 10:44:08
【问题描述】:

我之前问过这个问题,这个问题得到了回答,但是有人提出了一个建议,可以帮助我在前进的过程中避免犯类似的错误。

Adding Auto-Implemented Property to class using Roslyn

建议是我自下而上而不是自上而下构建语法树。有人可以提供一个小演示或链接来说明我将如何从头开始执行此操作吗?

这里又是代码:

var root = (CompilationUnitSyntax)document.GetSyntaxRoot();

    // Add the namespace
    var namespaceAnnotation = new SyntaxAnnotation();
    root = root.WithMembers(
        Syntax.NamespaceDeclaration(
            Syntax.ParseName("ACO"))
                .NormalizeWhitespace()
                .WithAdditionalAnnotations(namespaceAnnotation));
    document = document.UpdateSyntaxRoot(root);

    // Add a class to the newly created namespace, and update the document
    var namespaceNode = (NamespaceDeclarationSyntax)root
        .GetAnnotatedNodesAndTokens(namespaceAnnotation)
        .Single()
        .AsNode();

    var classAnnotation = new SyntaxAnnotation();
    var baseTypeName = Syntax.ParseTypeName("System.Windows.Forms.Form");
    SyntaxTokenList syntaxTokenList = new SyntaxTokenList()
        {
            Syntax.Token(SyntaxKind.PublicKeyword)
        };

    var newNamespaceNode = namespaceNode
        .WithMembers(
            Syntax.List<MemberDeclarationSyntax>(
                Syntax.ClassDeclaration("MainForm")
                    .WithAdditionalAnnotations(classAnnotation)
                    .AddBaseListTypes(baseTypeName)
                    .WithModifiers(Syntax.Token(SyntaxKind.PublicKeyword))));

    root = root.ReplaceNode(namespaceNode, newNamespaceNode).NormalizeWhitespace();
    document = document.UpdateSyntaxRoot(root);


    var attributes = Syntax.List(Syntax.AttributeDeclaration(Syntax.SeparatedList(Syntax.Attribute(Syntax.ParseName("STAThread")))));


    // Find the class just created, add a method to it and update the document
    var classNode = (ClassDeclarationSyntax)root
        .GetAnnotatedNodesAndTokens(classAnnotation)
        .Single()
        .AsNode();

        var syntaxList = Syntax.List<MemberDeclarationSyntax>(
                Syntax.MethodDeclaration(
                    Syntax.ParseTypeName("void"), "Main")
                    .WithModifiers(Syntax.TokenList(Syntax.Token(SyntaxKind.PublicKeyword)))
                    .WithAttributes(attributes)
                    .WithBody(
                        Syntax.Block()));
        syntaxList = syntaxList.Add(Syntax.PropertyDeclaration(Syntax.ParseTypeName("System.Windows.Forms.Timer"), "Ticker"));
        var newClassNode = classNode
            .WithMembers(syntaxList);

    root = root.ReplaceNode(classNode, newClassNode).NormalizeWhitespace();
    document = document.UpdateSyntaxRoot(root);

那么我将如何从头开始做同样的事情呢?

提前致谢,

鲍勃

附:我的财产也缺少“get; set;”里面的文字。有人可以评论我忘记添加导致此文本添加到属性中的内容吗?

【问题讨论】:

  • 要添加访问器,您需要将AccessorListSyntax 添加到包含两个访问器(AccessorDeclarationSyntaxes)的PropertyDeclarationSyntax,包括显式指定分号。

标签: c# roslyn


【解决方案1】:

信不信由你,我写了一个名为Roslyn Code Quoter 的工具来专门回答这个问题。

http://roslynquoter.azurewebsites.net

该工具可以使用任何 C# 程序并自动生成一个像 Matt 上面写的代码的 sn-p。由于它还完美地生成了包括所有空格在内的所有内容,因此代码可能会变得相当笨拙。但是你可以排除产生琐事的部分,然后在结果节点上调用 NormalizeWhitespace(),它会自动插入琐事,使代码格式正确。

为了完整起见,我发布了所有血腥细节的代码,以便您了解如何构造空白和所有这些小细节。

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()

【讨论】:

    【解决方案2】:

    这将在一个表达式中构建整个编译单元树。

    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())
                                    )
                            )
                    );
    

    当然,您不必将其作为单个表达式。我可以使用单独的局部变量来收集我想要的片段,然后将它们添加到包含语法片段的构造中。

    【讨论】:

    • 哇,这将为我节省大量的编码和调试时间!谢谢马特!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-05
    相关资源
    最近更新 更多