2012-07-05 13 views
11

Estoy tratando de aprender Roslyn construyendo una aplicación existente pero simple desde cero, que parece ser una forma productiva de aprender esto. De todos modos, tengo el siguiente código:Agregar Propiedad auto-implementada a la clase usando 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); 

Que emite el siguiente código en el IDocument.

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

A pesar de que debe ser de la misma familia (nótese que trataron de añadir la propiedad Timer)

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

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

Además, parece que el código que estoy escribiendo para un proceso tan simple parece excesivo. Además de mi pregunta principal, ¿pueden las personas ofrecer sugerencias sobre cómo puedo hacer esto de una manera más elegante? Tal vez un enlace a un blog, o fragmentos de código o algo así?


Resulta que tenía que cambiar esta línea:

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

Para esta línea:

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

Sin embargo, ahora consigo esta salida:

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

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

Ahora no obtengo el "get; set;" texto dentro de la propiedad. ¿Alguien sabe lo que me estoy perdiendo?

Respuesta

7

Creo que la razón por la cual no se agregó la propiedad es que SyntaxList s, como todo lo demás en Roslyn, son inmutables. ¿No devuelve Add() el SyntaxList actualizado? (No puedo verificar esto ahora, todavía no me he cambiado al CTP nuevo).

Y un código como este en Roslyn puede ser muy detallado, pero lo está haciendo más complicado de lo necesario. No es necesario actualizar root después de cada cambio, si crea el árbol de sintaxis de abajo arriba: primero cree los miembros de la clase, luego la clase y luego el espacio de nombres. Si lo haces, no tendrás que ocuparte de todas las anotaciones.

+0

El recordatorio de la inmutabilidad me llevó a darse cuenta de lo que estaba haciendo mal, que he publicado a continuación. Haré una pregunta por separado sobre cómo realmente construir mi Árbol de sintaxis particular de abajo arriba. – Beaker

+0

Aquí está el enlace a mi nueva pregunta sobre cómo construir mi Árbol de sintaxis desde cero como sugirió. http://stackoverflow.com/questions/11351977/roslyn-ctp-building-a-syntaxtree-from-the-ground-up – Beaker

+1

En esa otra pregunta suya he agregado un enlace a una herramienta llamada Quoter que puede ayudar en la generación automática de las llamadas API de sintaxis de Roslyn para cualquier programa: http://blogs.msdn.com/b/kirillosenkov/archive/2012/07/22/roslyn-code-quoter-tool-generating-syntax-tree-api- calls-for-any-c-program.aspx –

5

Utilizando la nueva API fluida (.Con ...() métodos) ahora se puede utilizar:

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