Construyendo un SyntaxTree desde cero

Anteriormente hice esta pregunta, la cual fue respondida, pero alguien me dio una sugerencia que podría ayudarme a evitar cometer errores similares a medida que avanzo.

Agregar propiedad auto-implementada a la clase usando Roslyn

La sugerencia fue que construyera el árbol de syntax de abajo hacia arriba y no de arriba hacia abajo. ¿Podría alguien proporcionar una pequeña demostración o un enlace que muestre cómo haría esto desde cero?

Aquí está el código de nuevo:

var root = (ComstacktionUnitSyntax)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( 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( Syntax.MethodDeclaration( Syntax.ParseTypeName("void"), "Main") .WithModifiers(Syntax.TokenList(Syntax.Token(SyntaxKind.PublicKeyword))) .WithAttributes(attributes) .WithBody( Syntax.Block())); syntaxList = 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); 

Entonces, ¿cómo haría lo mismo, pero desde el principio?

Gracias por adelantado,

Mover

PS A mi propiedad también le falta el “get; set;” texto dentro de ella ¿Alguien podría comentar sobre lo que olvido agregar que hace que este texto se agregue a la propiedad?

Esto construirá todo el árbol de unidades de comstackción en una expresión.

 var cu = SyntaxFactory.ComstacktionUnit() .AddMembers( SyntaxFactory.NamespaceDeclaration(Syntax.IdentifierName("ACO")) .AddMembers( SyntaxFactory.ClassDeclaration("MainForm") .AddBaseListTypes(SyntaxFactory.ParseTypeName("System.Windows.Forms.Form")) .WithModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword)) .AddMembers( Syntax.PropertyDeclaration(SyntaxFactory.ParseTypeName("System.Windows.Forms.Timer"), "Ticker") .AddAccessorListAccessors( SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)), SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))), SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("void"), "Main") .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword)) .AddAttributes(SyntaxFactory.AttributeDeclaration().AddAttributes(SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("STAThread")))) .WithBody(SyntaxFactory.Block()) ) ) ); 

Por supuesto, no tienes que hacerlo como una sola expresión. Podría haber usado variables locales separadas para recolectar las piezas que quería y luego agregarlas en la construcción de la pieza de syntax que contiene.

Lo creas o no, he escrito una herramienta llamada Roslyn Code Quoter especialmente para responder a esta pregunta.

http://roslynquoter.azurewebsites.net

La herramienta puede tomar cualquier progtwig C # y generar automáticamente un fragmento de código como Matt ha escrito anteriormente. Ya que también genera todo perfectamente incluyendo todo el espacio en blanco, el código puede ser bastante difícil de manejar. Pero puede excluir las partes que generan trivia, y luego simplemente llamar a NormalizeWhitespace () en el nodo resultante, insertará automáticamente la trivia para que el código tenga el formato correcto.

Para completar, estoy publicando el código en todos sus detalles sangrientos, para que puedas ver cómo construir espacios en blanco y todos esos pequeños detalles.

 ComstacktionUnit().WithMembers( SingletonList( NamespaceDeclaration( IdentifierName("ACO")) .WithMembers( SingletonList( ClassDeclaration("MainForm") .WithModifiers( TokenList( Token(SyntaxKind.PublicKeyword))) .WithBaseList( BaseList( SingletonSeparatedList( SimpleBaseType( QualifiedName( QualifiedName( QualifiedName( IdentifierName("System"), IdentifierName("Windows")), IdentifierName("Forms")), IdentifierName("Form")))))) .WithMembers( List( new MemberDeclarationSyntax[]{ PropertyDeclaration( QualifiedName( QualifiedName( QualifiedName( IdentifierName("System"), IdentifierName("Windows")), IdentifierName("Forms")), IdentifierName("Timer")), Identifier("Ticker")) .WithModifiers( TokenList( Token(SyntaxKind.PublicKeyword))) .WithAccessorList( AccessorList( List( new AccessorDeclarationSyntax[]{ AccessorDeclaration( SyntaxKind.GetAccessorDeclaration) .WithSemicolonToken( Token(SyntaxKind.SemicolonToken)), AccessorDeclaration( SyntaxKind.SetAccessorDeclaration) .WithSemicolonToken( Token(SyntaxKind.SemicolonToken))}))), MethodDeclaration( PredefinedType( Token(SyntaxKind.VoidKeyword)), Identifier("Main")) .WithAttributeLists( SingletonList( AttributeList( SingletonSeparatedList( Attribute( IdentifierName("STAThread")))))) .WithModifiers( TokenList( Token(SyntaxKind.PublicKeyword))) .WithBody( Block())})))))) .NormalizeWhitespace()