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

信じられないかもしれませんが、私は特にこの質問に答えるためにRoslynCodeQuoterと呼ばれるツールを作成しました。

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

これにより、コンパイルユニットツリー全体が1つの式に構築されます。

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 に答える