Создание синтаксиса с нуля
Ранее я задавал этот вопрос, на который был дан ответ, но кто-то дал предложение, которое могло бы помочь мне предотвратить подобные ошибки, когда я продвигаюсь вперед.
Добавление автоматически реализованного свойства в класс с использованием 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;" текст внутри него. Может ли кто-нибудь прокомментировать то, что я забываю добавить, что заставляет этот текст добавляться в свойство?
Ответы
Ответ 1
Это приведет к созданию всего дерева единиц компиляции в одном выражении.
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())
)
)
);
Конечно, вам не нужно делать это как одно выражение. Я мог бы использовать отдельные локальные переменные для сбора частей, которые я хотел, а затем добавил их в конструкцию содержащего синтаксиса.
Ответ 2
Верьте или нет, я написал инструмент, называемый Цитата Roslyn Code Quoter, чтобы ответить на этот вопрос.
http://roslynquoter.azurewebsites.net
Инструмент может принимать любую программу на С# и автоматически генерировать фрагмент кода, как написано выше. Поскольку он также генерирует все, что угодно, включая все пробелы, код может стать довольно громоздким. Но вы можете исключить части, которые генерируют мелочи, а затем просто вызвать NormalizeWhitespace() в результирующем node, он автоматически добавит мелочи, чтобы код был правильно отформатирован.
Для полноты я отправляю код во всех подробностях, чтобы вы могли видеть, как создавать пробелы и все эти маленькие детали.
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()