从头开始构建SyntaxTree

我之前曾问过这个问题,但是有人给出了一个建议,可以帮助我防止在我前进时犯下类似的错误。

使用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( 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); 

那我怎么做同样的事情,但从头开始?

提前致谢,

短发

PS我的财产也缺少“get; set;” 其中的文字。 有人可以评论我忘记添加哪些内容会导致将此文本添加到属性中吗?

这将在一个表达式中构建整个编译单元树。

 var cu = SyntaxFactory.CompilationUnit() .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()) ) ) ); 

当然,您不必将其作为单个表达式来执行。 我可以使用单独的局部变量来收集我想要的部分,然后将它们添加到包含语法部分的构造中。

信不信由你,我写了一个名为Roslyn Code Quoter的工具,特别是回答这个问题。

http://roslynquoter.azurewebsites.net

该工具可以采用任何C#程序,并自动生成像Matt上面所写的代码片段。 由于它还可以完美地生成包括所有空格在内的所有内容,因此代码可能会变得相当笨拙。 但是你可以排除生成琐事的部分,然后在结果节点上调用NormalizeWhitespace(),它会自动插入琐事,以便正确格式化代码。

为了完整起见,我在其所有的血腥细节中发布代码,以便您可以看到如何构造空白和所有这些小细节。

 CompilationUnit().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()