Ajouter une propriété auto-implémentée à la classe en utilisant Roslyn

j'essaie d'apprendre Roslyn en construisant une application existante mais simple à partir de la base, ce qui semble être une façon productive d'apprendre cela. Quoi qu'il en soit, j'ai le code suivant:

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

qui affiche le code suivant dans L'IDocument.

namespace ACO
{
    public class MainForm : System.Windows.Forms.Form
    {
        [STAThread]
        public void Main()
        {
        }
    }
}

bien qu'il devrait ressembler plus à ceci (notez que j'ai essayé d'ajouter la propriété Timer)

namespace ACO
{
    public class MainForm : System.Windows.Forms.Form
    {
    public System.Windows.Forms.Timer Ticker {get; set;}

        [STAThread]
        public void Main()
        {
        }
    }
}

aussi, il semble que le code que j'écris pour un processus aussi simple semble excessif. En plus de ma question principale, est-ce que les gens peuvent m'offrir des suggestions sur la façon dont je peux m'y prendre de façon plus élégante? Peut-être un lien vers un blog, ou des morceaux de code ou quelque chose?


Il s'avère que j'avais besoin de changer cette ligne:

syntaxList.Add(Syntax.PropertyDeclaration(Syntax.ParseTypeName("System.Windows.Forms.Timer"), "Ticker"));

sur cette ligne:

syntaxList = syntaxList.Add(Syntax.PropertyDeclaration(Syntax.ParseTypeName("System.Windows.Forms.Timer"), "Ticker"));

cependant, maintenant je reçois cette sortie:

namespace ACO
{
    public class MainForm : System.Windows.Forms.Form
    {
        [STAThread]
        public void Main()
        {
        }

        System.Windows.Forms.Timer Ticker
        {
        }
    }
}

maintenant je suis ne pas obtenir le texte "get; set;" dans la propriété. Personne ne sait ce que je suis absent?

11
demandé sur casperOne 2012-07-05 04:48:38

2 réponses

je pense que la raison pour laquelle la propriété n'a pas été ajoutée est que SyntaxList s, comme tout le reste dans Roslyn, sont immuables. Add() ne renvoie-t-il pas la mise à jour SyntaxList ? (Je ne peux pas le vérifier pour le moment, je n'ai pas encore passé à la nouvelle version de la CTP.)

et un code comme celui-ci dans Roslyn peuvent être très verbeux, mais vous le rendez plus compliqué que nécessaire. Vous n'avez pas à mettre à jour root après chaque changement, si vous construisez l'arbre de syntaxe de bas en haut: créez d'abord les membres de la catégorie, la classe, puis l'espace de noms. Si vous le faites, vous n'aurez pas à traiter avec toutes les annotations.

7
répondu svick 2012-07-05 08:03:38

utilisant la nouvelle API fluent (.Avec...()) vous pouvez maintenant utiliser:

Syntax.PropertyDeclaration(Syntax.ParseTypeName("int"), "MyProperty")
      .WithAccessorList(
          Syntax.AccessorList(
              Syntax.List(
                  Syntax.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
                        .WithSemicolonToken(Syntax.Token(SyntaxKind.SemicolonToken)),
                  Syntax.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
                        .WithSemicolonToken(Syntax.Token(SyntaxKind.SemicolonToken)))));
5
répondu Maciej Wozniak 2013-06-16 20:14:48