2012-07-05 8 views
11

Я пытаюсь изучить Roslyn, создав существующее, но простое приложение с нуля, что, кажется, является эффективным способом узнать это. Во всяком случае, у меня есть следующий код:Добавление объекта Auto-Implemented в класс с использованием 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() 
     { 
     } 
    } 
} 

Хотя это должно выглядеть следующим образом (обратите внимание, я пытался добавить свойство Timer)

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 s, как и все остальное в 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, который может помочь в автоматическом генерации синтаксиса API Roslyn для любой программы: http://blogs.msdn.com/b/kirillosenkov/archive/2012/07/22/roslyn-code-quoter-tool-generating-syntax-tree-api- вызовы-для-любой-с-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))))); 

 Смежные вопросы

  • Нет связанных вопросов^_^