25

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

使用 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);

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

提前致谢,

鲍勃

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

4

2 回答 2

18

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

http://roslynquoter.azurewebsites.net

该工具可以采用任何 C# 程序并自动生成一段代码,就像 Matt 上面写的那样。由于它还可以完美地生成包括所有空格在内的所有内容,因此代码可能会变得相当笨拙。但是您可以排除生成琐事的部分,然后在结果节点上调用 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()
于 2012-07-23T05:29:15.623 回答
17

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

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

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

于 2012-07-05T21:17:50.760 回答