Wat is de meest efficiënte manier om een ​​IDocument vanaf het begin op te bouwen?

Ik zou stap voor stap een nieuw IDocument-object willen opbouwen, waarbij de volgende klasse als een specifiek voorbeeld zou worden gebruikt. Je kunt beginnen met elk object dat je leuk vindt en alle tussenliggende objecten gebruiken die je leuk vindt, zolang het resulterende object een IDocument is dat aan het eind de volledige klasse vertegenwoordigt.

Stap # 1: voeg een nieuwe naamruimte toe met de naam MyNamespace. Het uitprinten van het huidige object zou er op dit moment zo uit moeten zien:

namespace MyNamespace
{
}

Stap # 2: Voeg een nieuwe klasse toe aan deze naamruimte met de naam MyClass. Het uitprinten van het huidige object zou er op dit moment zo uit moeten zien:

namespace MyNamespace
{
    public class MyClass
    {
    }
}

Stap # 3: voeg een nieuwe methode toe aan deze klasse genaamd MyMethod. Het uitprinten van het huidige object zou er op dit moment zo uit moeten zien:

namespace MyNamespace
    {
        public class MyClass
        {
            public void MyMethod()
            {
            }
        }
    }

Het probleem dat ik hiermee heb, is dat er een aantal manieren zijn waarop je dit theoretisch zou kunnen doen, of ten minste ten onrechte concluderen dat je dit zou kunnen aanpakken. Eindeloze methoden en constructors in allerlei verschillende objecten zoals WithChanges, UpdateDocument, methoden op de verschillende Syntax-objecten, ParseCompilationUnit, etc.

Eigenlijk wil ik dit op een incrementele manier opbouwen met een duidelijk object bij elke stap dat ik bijvoorbeeld naar de console kan afdrukken, niet één grote uitspraak die dit hele ding in één regel creëert. Ik heb alle documentatie die bij de juni-release van de CTP is meegeleverd meerdere keren gelezen en zoals ik al zei, ben ik verdwaald in de schijnbaar eindeloze combinaties van verschillende constructeurs en methoden. Ik ben ook geïnteresseerd in een manier die ook rekening houdt met de prestaties.

2

1 antwoord

Om alles stukje bij beetje op te bouwen, moet je iets als de onderstaande code schrijven. Ik zou ook willen dat je een kijkje neemt naar het voorbeeld ImplementINotifyPropertyChanged, omdat het redelijk veel syntaxis bouwt en herschrijft. Merk op dat er, zoals u suggereert, verschillende manieren zijn om dit te doen. Dat komt omdat de API is ontworpen om scenario's zoals editors te ondersteunen, dus u kunt dit bouwen door tekstwijzigingen toe te passen voor elke toetsaanslag van een gebruiker die ook typt. Welke API de juiste is, hangt af van wat u probeert te bereiken.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;
using Roslyn.Services;
using Roslyn.Services.CSharp;

class Program
{
    static void Main(string[] args)
    {
       //Create the solution with an empty document
        ProjectId projectId;
        DocumentId documentId;
        var solution = Solution.Create(SolutionId.CreateNewId())
            .AddProject("MyProject", "MyProject", LanguageNames.CSharp, out projectId)
            .AddDocument(projectId, @"C:\file.cs", string.Empty, out documentId);

        var document = solution.GetDocument(documentId);
        var root = (CompilationUnitSyntax)document.GetSyntaxRoot();

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

        Console.WriteLine("-------------------");
        Console.WriteLine("With Namespace");
        Console.WriteLine(document.GetText().GetText());

       //Find our namespace, add a class to it, and update the document
        var namespaceNode = (NamespaceDeclarationSyntax)root
            .GetAnnotatedNodesAndTokens(namespaceAnnotation)
            .Single()
            .AsNode();

        var classAnnotation = new SyntaxAnnotation();
        var newNamespaceNode = namespaceNode
            .WithMembers(
                Syntax.List(
                    Syntax.ClassDeclaration("MyClass")
                        .WithAdditionalAnnotations(classAnnotation)));
        root = root.ReplaceNode(namespaceNode, newNamespaceNode).NormalizeWhitespace();
        document = document.UpdateSyntaxRoot(root);

        Console.WriteLine("-------------------");
        Console.WriteLine("With Class");
        Console.WriteLine(document.GetText().GetText());

       //Find the class, add a method to it and update the document
        var classNode = (ClassDeclarationSyntax)root
            .GetAnnotatedNodesAndTokens(classAnnotation)
            .Single()
            .AsNode();
        var newClassNode = classNode
            .WithMembers(
                Syntax.List(
                    Syntax.MethodDeclaration(
                        Syntax.ParseTypeName("void"),
                        "MyMethod")
                        .WithBody(
                            Syntax.Block())));
        root = root.ReplaceNode(classNode, newClassNode).NormalizeWhitespace();
        document = document.UpdateSyntaxRoot(root);

        Console.WriteLine("-------------------");
        Console.WriteLine("With Method");
        Console.WriteLine(document.GetText().GetText());
    }
}
5
toegevoegd
Wauw, ik ging hier op een uiterst inefficiënte manier mee om. Ik zal de door jou genoemde steekproef bekijken. Bedankt voor je hulp, ik heb net veel van je antwoord geleerd!
toegevoegd de auteur Beaker, de bron
Blijkbaar is er een nog efficiëntere manier om de SyntaxTree vanaf de grond op te bouwen, wat het antwoord was op deze vraag: stackoverflow.com/questions/11351977/…
toegevoegd de auteur Beaker, de bron
Voor de vraag die ik stelde was dit het juiste antwoord, ik wees alleen op een alternatief voor mensen die de tussenstappen niet nodig hadden.
toegevoegd de auteur Beaker, de bron
Natuurlijk, maar uw vraag heeft expliciet gevraagd om de tussenliggende stappen.
toegevoegd de auteur Kevin Pilch, de bron