从一开始就建立IDocument的最有效方法是什么

时间:2012-06-24 02:40:03

标签: c# .net c#-4.0 roslyn

我想使用以下类作为一个具体示例逐步构建一个新的IDocument对象。您可以从任何您喜欢的对象开始,并使用您喜欢的任何中间对象,只要生成的对象是一个IDocument,它代表最后的完整类。

步骤1:添加一个名为MyNamespace的新命名空间。 打印出当前对象应该如下所示:

namespace MyNamespace
{
}

步骤2:向名为MyClass的名称空间添加一个新类。 打印出当前对象应该如下所示:

namespace MyNamespace
{
    public class MyClass
    {
    }
}

步骤3:向此类添加一个名为MyMethod的新方法。 打印出当前对象应该如下所示:

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

我遇到的问题是,理论上似乎有很多方法可以解决这个问题,或者至少错误地认为你可以解决这个问题。各种不同对象中的无尽方法和构造函数,如WithChanges,UpdateDocument,各种语法对象上的方法,ParseCompilationUnit等。

基本上,我想以增量的方式构建它,在每个步骤都有一个不同的对象,例如,我可以打印到控制台,而不是一个在一行中创建整个事物的大声明。我已经多次阅读了6月发布的CTP所附的所有文档,正如我所提到的,我在各种构造函数和方法的看似无穷无尽的组合中迷失了。此外,我也对将性能考虑在内的方式感兴趣。

1 个答案:

答案 0 :(得分:5)

按照你的建议,我会像下面的代码那样编写一些零碎的东西。我还鼓励您查看一下ImplementINotifyPropertyChanged示例,因为它可以很好地完成语法构造和重写。请注意,正如您所建议的那样,您可以通过多种方式执行此操作。这是因为API旨在支持编辑器等场景,因此您可以通过对用户键入的每次击键应用文本更改来构建它。哪种API是正确的,取决于您要实现的目标。

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