【问题标题】:Adding Auto-Implemented Property to class using Roslyn使用 Roslyn 将自动实现的属性添加到类
【发布时间】:2012-07-05 00:48:38
【问题描述】:

我正在尝试通过从头开始构建一个现有但简单的应用程序来学习 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);

在 IDocument 中输出以下代码。

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

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

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

        [STAThread]
        public void Main()
        {
        }
    }
}

此外,我为这样一个简单的过程编写的代码似乎有些过分。除了我的主要问题之外,人们能否就我如何以更优雅的方式解决这个问题提出建议?也许是博客的链接,或者代码 sn-ps 什么的?


原来我需要更改这一行:

syntaxList.Add(Syntax.PropertyDeclaration(Syntax.ParseTypeName("System.Windows.Forms.Timer"), "Ticker"));

到这一行:

syntaxList = syntaxList.Add(Syntax.PropertyDeclaration(Syntax.ParseTypeName("System.Windows.Forms.Timer"), "Ticker"));

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

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

        System.Windows.Forms.Timer Ticker
        {
        }
    }
}

现在我没有得到“get; set;”属性中的文本。有谁知道我错过了什么?

【问题讨论】:

    标签: c# automatic-properties roslyn


    【解决方案1】:

    我认为未添加该属性的原因是 SyntaxLists 与 Roslyn 中的其他所有内容一样,是不可变的。 Add() 不会返回更新后的SyntaxList 吗? (我现在无法验证,我还没有切换到新的 CTP。)

    在 Roslyn 中这样的代码可能非常冗长,但你让它变得比必要的复杂。您不必在每次更改后更新root,如果您自下而上构建语法树:首先创建类的成员,然后是类,然后是命名空间。如果你这样做,你根本不需要处理所有的注释。

    【讨论】:

    • 您对不变性的提醒使我意识到我在下面发布的错误。我将问一个单独的问题,关于如何从下到上实际构建我的特定语法树。
    • 这是我的新问题的链接,关于如何按照您的建议从头开始构建语法树。 stackoverflow.com/questions/11351977/…
    • 在你的另一个问题中,我添加了一个名为 Quoter 的工具的链接,该工具可以帮助为任何程序自动生成 Roslyn 语法 API 调用:blogs.msdn.com/b/kirillosenkov/archive/2012/07/22/…
    【解决方案2】:

    使用新的 fluent 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)))));
    

    【讨论】:

      猜你喜欢
      • 2012-03-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-28
      • 1970-01-01
      • 2020-03-12
      • 2016-01-02
      相关资源
      最近更新 更多