【问题标题】:Adding custom attributes to C# classes using Roslyn使用 Roslyn 向 C# 类添加自定义属性
【发布时间】:2012-03-01 13:41:10
【问题描述】:

考虑文件“MyClass.cs”中的以下类

using System;

public class MyClass : Entity<long>
{
    public long Id
    {
        get;
        set;
    }

    [Required]
    public string Name
    {
        get;
        set;
    }

    public string Slug
    {
        get;
        set;
    }

    public DateTime CreatedOn
    {
        get;
        private set;
    }

    public DateTime UpdatedOn
    {
        get;
        private set;
    }

    /* ... */
}

目前我手动创建如下所示的数据协定类:

[DataContract(Namespace = "http://example.com/", Name = "MyClass")]
public sealed class MyClass
{
    [DataMember(EmitDefaultValue = false, Name = "Id")]
    public long Id
    {
        get;
        set;
    }

    [DataMember(EmitDefaultValue = false, Name = "Name", IsRequired = true)]
    public string Name
    {
        get;
        set;
    }

    [DataMember(EmitDefaultValue = false, Name = "Slug")]
    public string Slug
    {
        get;
        set;
    }

    [DataMember(EmitDefaultValue = false, Name = "CreatedOn")]
    public DateTime CreatedOn
    {
        get;
        set;
    }

    [DataMember(EmitDefaultValue = false, Name = "UpdatedOn")]
    public DateTime UpdatedOn
    {
        get;
        set;
    }
}

我想用 Roslyn 重写“MyClass.cs”,使它看起来像我手工创建的类。目前我有以下内容:

using System;
using System.IO;
using Roslyn.Compilers.CSharp;

internal class Program
{
    private static void Main()
    {
        var reader = new StreamReader(@"..\..\MyClass.cs");
        var source = reader.ReadToEnd();
        var tree = SyntaxTree.ParseCompilationUnit(source);
        var rewriter = new MyRewriter();
        var newRoot = rewriter.Visit(tree.Root);
        Console.WriteLine(newRoot.Format());
    }
}

public class MyRewriter : SyntaxRewriter
{
    protected override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node)
    {
        var declaration = (TypeDeclarationSyntax) base.VisitClassDeclaration(node);

        return ((ClassDeclarationSyntax) declaration).Update(
            declaration.Attributes,
            Syntax.TokenList(Syntax.Token(SyntaxKind.PublicKeyword), Syntax.Token(SyntaxKind.SealedKeyword)),
            declaration.Keyword,
            declaration.Identifier,
            declaration.TypeParameterListOpt,
            null,
            declaration.ConstraintClauses,
            declaration.OpenBraceToken,
            declaration.Members,
            declaration.CloseBraceToken,
            declaration.SemicolonTokenOpt);
    }

    protected override SyntaxNode VisitPropertyDeclaration(PropertyDeclarationSyntax node)
    {
        var typeSyntax = node.Type;

        if (node.Identifier.ValueText == "Id")
        {
            typeSyntax = Syntax.IdentifierName("string");
        }

        var newProperty = Syntax.PropertyDeclaration(
            modifiers: Syntax.TokenList(Syntax.Token(SyntaxKind.PublicKeyword)),
            type: typeSyntax,
            identifier: node.Identifier,
            accessorList: Syntax.AccessorList(
                accessors: Syntax.List(
                    Syntax.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration, 
                    semicolonTokenOpt: Syntax.Token(SyntaxKind.SemicolonToken)),
                    Syntax.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration,
                    semicolonTokenOpt: Syntax.Token(SyntaxKind.SemicolonToken))
                    )
                )
            );

        return newProperty;
    }
}

我一直在尝试找到一种将 DataMember 和 DataContract 自定义属性添加到 MyClass 的方法,但没有成功。如何添加自定义属性?

【问题讨论】:

  • 按照我阅读 this MSDN 线程的方式,我想说 Roslyn 不支持自定义属性。你有没有看到其他情况?
  • Roslyn 确实支持语法级别的属性,但不支持语义
  • 有一个 AttributeDeclarationSyntax 类,该类和属性都有一个属性成员,但我找不到如何构造它的示例。您还可以使用 SyntaxRewiter 重写属性。这是example 如何使用它。所以我认为它支持,但我可能错了。
  • SyntaxTree.ParseCompilationUnit(source) here ->SyntaxTree 不包含“ParseCompilationUnit”的定义

标签: c# code-generation roslyn


【解决方案1】:

Syntax.PropertyDeclaration 方法的参数之一是应用于属性的属性列表。像所有Syntax 元素一样,它是使用静态SyntaxFactory 类上的工厂方法构造的。

Roslyn Quoter 可以方便地了解如何使用 Roslyn 生成语法。

在您的特定示例中,重写器的 VisitPropertyDeclaration 方法应类似于:

using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
...

    protected override SyntaxNode VisitPropertyDeclaration(PropertyDeclarationSyntax node)
{
    var typeSyntax = node.Type;

    if (node.Identifier.ValueText == "Id")
    {
        typeSyntax = SyntaxFactory.IdentifierName("string");
    }

    var newProperty = PropertyDeclaration(
                PredefinedType(
                    Token(SyntaxKind.LongKeyword)),
                Identifier("Id"))
            .WithModifiers(
                TokenList(
                    Token(SyntaxKind.PublicKeyword)))
            .WithAccessorList(
                AccessorList(
                    List(new AccessorDeclarationSyntax[]{
                        AccessorDeclaration(
                            SyntaxKind.GetAccessorDeclaration)
                        .WithSemicolonToken(
                            Token(SyntaxKind.SemicolonToken)),
                        AccessorDeclaration(
                            SyntaxKind.SetAccessorDeclaration)
                        .WithSemicolonToken(
                            Token(SyntaxKind.SemicolonToken))})))
            .NormalizeWhitespace();

    return newProperty;
}       

【讨论】:

  • 我注意到了,但我不知道如何初始化它,因此提出了问题。
  • 正是我想要的。谢谢。
  • 您能否使用最新的 Roslyn 语法更新您的答案? 10x
  • 此语法看起来不再受支持。既然他们已经密封了所有主要课程,有机会看看它是如何完成的吗?
  • 使用最新语法更新。您可以使用roslynquoter.azurewebsites.net 自己轻松完成此操作
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-09
  • 2018-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多