2012-07-05 47 views
11

我试图通过从头开始构建现有的但简单的应用程序来学习Roslyn,这似乎是一种有效的方法来学习这一点。无论如何,我有以下代码:使用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.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); 

它在IDocument中输出以下代码。

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

虽然它看起来应该更多这样的(注意我尝试添加定时器属性)

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

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

而且,看来我写这样一个简单的过程代码似乎过度。除了我的主要问题之外,人们可以就如何以更优雅的方式来解决这个问题提供建议吗?也许链接到博客,或代码片段或什么?


事实证明,我需要改变这一行:

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

这一行:

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

不过,现在我得到这样的输出:

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

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

现在我没有得到“get; set;”文本内的文本。有谁知道我错过了什么?

回答

7

我认为该物业未被添加的原因是SyntaxList与Roslyn中的其他所有物品一样是不可变的。 Add()是否返回更新的SyntaxList? (我现在无法验证这一点,但我还没有切换到新的CTP。)

Roslyn中的代码可能非常冗长,但是它使得代码更加复杂。如果从下到上构建语法树,则不必在每次更改后更新root:首先创建类的成员,然后创建类,然后创建名称空间。如果你这样做,你就不必处理所有的注释。

+0

你永恒的提醒使我意识到我在做什么错,我贴在下面。我会问一个关于如何从下到上实际构建特定语法树的单独问题。 – Beaker

+0

这里是我的新问题的链接,关于如何根据您的建议从头开始构建语法树。 http://stackoverflow.com/questions/11351977/roslyn-ctp-building-a-syntaxtree-from-the-ground-up – Beaker

+1

在你的其他问题中,我添加了一个名为Quoter的工具的链接,可以帮助你在为任何程序自动生成Roslyn语法API调用: http://blogs.msdn.com/b/kirillosenkov/archive/2012/07/22/roslyn-code-quoter-tool-generating-syntax-tree-api-要求换任何-C-program.aspx –

5

使用新的API流利(。随着...()方法),您现在可以使用:

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