使用Roslyn生成代码时,如何在一行上获得自动属性?

时间:2018-06-28 12:13:22

标签: c# code-generation roslyn

我有以下部分代码,用于根据面向客户的研讨会等使用的excel文件生成数据合同。

    private PropertyDeclarationSyntax[] GenerateProperties()
    {
        var props = new List<PropertyDeclarationSyntax>();
        props.Add(SF.PropertyDeclaration(SF.ParseTypeName("IMigrationInformation"), "MigrationInformation")
            .AddModifiers(SF.Token(SyntaxKind.PublicKeyword), SF.Token(SyntaxKind.OverrideKeyword))
            .AddAccessorListAccessors(
                SF.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
                    .WithBody(SF.Block(SF.ReturnStatement(SF.ObjectCreationExpression(SF.ParseTypeName($"{Form.RegistryName}MigrationInformation")))))
            ));
        foreach (var field in Form.AllDataFields().Where(f => f.FieldTypeInfo != null))
        {
            props.Add(SF.PropertyDeclaration(SF.ParseTypeName(field.FieldTypeInfo.BackingType.Name), field.SafeName)
                .AddModifiers(SF.Token(SyntaxKind.PublicKeyword))
                .AddAccessorListAccessors(
                    SF.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration).WithSemicolonToken(SF.Token(SyntaxKind.SemicolonToken)),
                    SF.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration).WithSemicolonToken(SF.Token(SyntaxKind.SemicolonToken))
                ));
        }

        return props.ToArray();
    }

该代码通过一个小障碍就可以很好地工作。生成的代码如下:

public string VariableName
{
    get;
    set;
}

我真的希望它看起来像这样:

public string VariableName { get; set; }

有没有人知道如何做到这一点?

2 个答案:

答案 0 :(得分:1)

作为一种简单的解决方案(另一种方法,使用正确的琐事创建节点和令牌),只需对要在一行中表示的节点使用SyntaxNodeExtensions.NormalizeWhitespace(...)

...
foreach (var field in Form.AllDataFields().Where(f => f.FieldTypeInfo != null))
{
    props.Add(SF.PropertyDeclaration(SF.ParseTypeName(field.FieldTypeInfo.BackingType.Name), field.SafeName)
        .AddModifiers(SF.Token(SyntaxKind.PublicKeyword))
        .AddAccessorListAccessors(
            SF.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration).WithSemicolonToken(SF.Token(SyntaxKind.SemicolonToken)),
            SF.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration).WithSemicolonToken(SF.Token(SyntaxKind.SemicolonToken))
        ).NormalizeWhitespace(indentation: "", eol: " "));
}

答案 1 :(得分:0)

您可以实现CSharpSyntaxRewriter并将其应用于父SyntaxNode:

public static class WhitespaceFormatter
{
    public static SyntaxNode NormalizeWhitespacesSingleLineProperties(this SyntaxNode node) => 
        node.NormalizeWhitespace().SingleLineProperties();

    public static SyntaxNode SingleLineProperties(this SyntaxNode node) => new SingleLinePropertyRewriter().Visit(node);

    class SingleLinePropertyRewriter : CSharpSyntaxRewriter
    {
        public override SyntaxNode VisitPropertyDeclaration(PropertyDeclarationSyntax node) =>
            node.NormalizeWhitespace(indentation: "", eol: " ")
                .WithLeadingTrivia(node.GetLeadingTrivia())
                .WithTrailingTrivia(node.GetTrailingTrivia());
    }
}

使用NormalizeWhitespacesSingleLineProperties将默认空格应用于除将要写入一行的属性声明以外的所有内容。确保以后不要再在节点上调用FormatNormalizeWhitespace(),因为这将再次使属性声明变得混乱。