使用Roslyn将自动实现的属性添加到类

Bea*_*ker 11 c# automatic-properties roslyn

我试图通过从头开始构建现有但简单的应用程序来学习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.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);
Run Code Online (Sandbox Code Playgroud)

它在IDocument中输出以下代码.

namespace ACO
{
    public class MainForm : System.Windows.Forms.Form
    {
        [STAThread]
        public void Main()
        {
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然看起来应该更像这样(注意我试图添加Timer属性)

namespace ACO
{
    public class MainForm : System.Windows.Forms.Form
    {
    public System.Windows.Forms.Timer Ticker {get; set;}

        [STAThread]
        public void Main()
        {
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

而且,似乎我为这样一个简单的过程编写的代码似乎过多了.除了我的主要问题,人们可以提供有关如何以更优雅的方式解决这个问题的建议吗?也许链接到博客,或代码片段或什么?


事实证明我需要改变这一行:

syntaxList.Add(Syntax.PropertyDeclaration(Syntax.ParseTypeName("System.Windows.Forms.Timer"), "Ticker"));
Run Code Online (Sandbox Code Playgroud)

到这一行:

syntaxList = syntaxList.Add(Syntax.PropertyDeclaration(Syntax.ParseTypeName("System.Windows.Forms.Timer"), "Ticker"));
Run Code Online (Sandbox Code Playgroud)

但是,现在我得到这个输出:

namespace ACO
{
    public class MainForm : System.Windows.Forms.Form
    {
        [STAThread]
        public void Main()
        {
        }

        System.Windows.Forms.Timer Ticker
        {
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我没有得到"得到;设定;" 财产内的文字.有谁知道我错过了什么?

svi*_*ick 7

我认为没有添加属性的原因是SyntaxLists,就像Roslyn中的其他内容一样,是不可变的.不Add()退货更新SyntaxList?(我现在无法验证这一点,我还没有切换到新的CTP.)

在Roslyn中这样的代码可能非常冗长,但是你要使它比必要的更复杂.root如果从下到上构建语法树,则不必在每次更改后更新:首先创建类的成员,然后创建类,然后创建名称空间.如果你这样做,你将不必处理所有的注释.


Mac*_*iak 6

使用新的流畅API(.With ...()方法),您现在可以使用:

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)))));
Run Code Online (Sandbox Code Playgroud)