我之前曾问过这个问题,这个问题得到了解答,但是有人给出了一个建议,可以帮助我防止在我前进的过程中犯类似的错误。
Adding Auto-Implemented Property to class using 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 = 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);
那我怎么做同样的事情,但从头开始?
提前致谢,
鲍勃
P.S。我的财产也缺少“get; set;”其中的文字。有人可以评论我忘记添加哪些内容会导致将此文本添加到属性中吗?
答案 0 :(得分:17)
这将在一个表达式中构建整个编译单元树。
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())
)
)
);
当然,您不必将其作为单个表达式进行。我可以使用单独的局部变量来收集我想要的部分,然后将它们添加到包含语法部分的构造中。
答案 1 :(得分:15)
信不信由你,我写了一个名为Roslyn Code Quoter的工具来回答这个问题。
http://roslynquoter.azurewebsites.net
该工具可以使用任何C#程序并自动生成Matt上面写的代码片段。由于它还可以完美地生成包括所有空格在内的所有内容,因此代码可能会变得相当笨拙。但是你可以排除生成琐事的部分,然后在结果节点上调用NormalizeWhitespace(),它会自动插入琐事,以便正确格式化代码。
为了完整起见,我发布了所有血腥细节的代码,以便您可以看到如何构建空白和所有这些小细节。
CompilationUnit().WithMembers(
SingletonList<MemberDeclarationSyntax>(
NamespaceDeclaration(
IdentifierName("ACO"))
.WithMembers(
SingletonList<MemberDeclarationSyntax>(
ClassDeclaration("MainForm")
.WithModifiers(
TokenList(
Token(SyntaxKind.PublicKeyword)))
.WithBaseList(
BaseList(
SingletonSeparatedList<BaseTypeSyntax>(
SimpleBaseType(
QualifiedName(
QualifiedName(
QualifiedName(
IdentifierName("System"),
IdentifierName("Windows")),
IdentifierName("Forms")),
IdentifierName("Form"))))))
.WithMembers(
List<MemberDeclarationSyntax>(
new MemberDeclarationSyntax[]{
PropertyDeclaration(
QualifiedName(
QualifiedName(
QualifiedName(
IdentifierName("System"),
IdentifierName("Windows")),
IdentifierName("Forms")),
IdentifierName("Timer")),
Identifier("Ticker"))
.WithModifiers(
TokenList(
Token(SyntaxKind.PublicKeyword)))
.WithAccessorList(
AccessorList(
List<AccessorDeclarationSyntax>(
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<AttributeListSyntax>(
AttributeList(
SingletonSeparatedList<AttributeSyntax>(
Attribute(
IdentifierName("STAThread"))))))
.WithModifiers(
TokenList(
Token(SyntaxKind.PublicKeyword)))
.WithBody(
Block())}))))))
.NormalizeWhitespace()