Ajouter une propriété auto-implémentée à la classe en utilisant Roslyn
j'essaie d'apprendre Roslyn en construisant une application existante mais simple à partir de la base, ce qui semble être une façon productive d'apprendre cela. Quoi qu'il en soit, j'ai le code suivant:
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);
qui affiche le code suivant dans L'IDocument.
namespace ACO
{
public class MainForm : System.Windows.Forms.Form
{
[STAThread]
public void Main()
{
}
}
}
bien qu'il devrait ressembler plus à ceci (notez que j'ai essayé d'ajouter la propriété Timer)
namespace ACO
{
public class MainForm : System.Windows.Forms.Form
{
public System.Windows.Forms.Timer Ticker {get; set;}
[STAThread]
public void Main()
{
}
}
}
aussi, il semble que le code que j'écris pour un processus aussi simple semble excessif. En plus de ma question principale, est-ce que les gens peuvent m'offrir des suggestions sur la façon dont je peux m'y prendre de façon plus élégante? Peut-être un lien vers un blog, ou des morceaux de code ou quelque chose?
Il s'avère que j'avais besoin de changer cette ligne:
syntaxList.Add(Syntax.PropertyDeclaration(Syntax.ParseTypeName("System.Windows.Forms.Timer"), "Ticker"));
sur cette ligne:
syntaxList = syntaxList.Add(Syntax.PropertyDeclaration(Syntax.ParseTypeName("System.Windows.Forms.Timer"), "Ticker"));
cependant, maintenant je reçois cette sortie:
namespace ACO
{
public class MainForm : System.Windows.Forms.Form
{
[STAThread]
public void Main()
{
}
System.Windows.Forms.Timer Ticker
{
}
}
}
maintenant je suis ne pas obtenir le texte "get; set;" dans la propriété. Personne ne sait ce que je suis absent?
2 réponses
je pense que la raison pour laquelle la propriété n'a pas été ajoutée est que SyntaxList
s, comme tout le reste dans Roslyn, sont immuables. Add()
ne renvoie-t-il pas la mise à jour SyntaxList
? (Je ne peux pas le vérifier pour le moment, je n'ai pas encore passé à la nouvelle version de la CTP.)
et un code comme celui-ci dans Roslyn peuvent être très verbeux, mais vous le rendez plus compliqué que nécessaire. Vous n'avez pas à mettre à jour root
après chaque changement, si vous construisez l'arbre de syntaxe de bas en haut: créez d'abord les membres de la catégorie, la classe, puis l'espace de noms. Si vous le faites, vous n'aurez pas à traiter avec toutes les annotations.
utilisant la nouvelle API fluent (.Avec...()) vous pouvez maintenant utiliser:
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)))));