2012-02-09 8 views
10

Si consideri il seguente classe in un file "MyClass.cs"Aggiunta personalizzata per le classi C# utilizzando Roslyn

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; 
    } 

    /* ... */ 
} 

Attualmente creo manualmente i dati classi di contratto guardando come segue:

[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; 
    } 
} 

I' Mi piacerebbe usare Roslyn per riscrivere "MyClass.cs" in modo che assomigli alla classe che creo a mano. Attualmente ho il seguente:

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; 
    } 
} 

ho cercato di trovare un modo per aggiungere attributi DataMember e DataContract personalizzato per MyClass, ma non hanno avuto successo. Come si aggiungono gli attributi personalizzati?

+0

Il modo in cui ho letto [questo] (http://social.msdn.microsoft.com/Forums/en- US/roslyn/thread/f5adeaf0-49d0-42dc-861b-0f6ffd731825) Thread MSDN, direi che Roslyn non supporta gli attributi personalizzati. Hai visto qualcosa che indica il contrario? –

+0

Roslyn supporta gli attributi a livello di sintassi, non solo la semantica –

+0

Esiste una classe AttributeDeclarationSyntax e sia la classe che le proprietà hanno un membro attributi, ma non riesco a trovare un esempio su come costruirlo. Puoi anche riscrivere gli attributi con un SyntaxRewiter. Ecco un [esempio] (http://www.mindscapehq.com/blog/index.php/2011/10/20/in-bed-with-roslyn/) come usarlo. Quindi penserei che sia supportato, ma potrei sbagliarmi. – bloudraak

risposta

10

Uno dei parametri del metodo Syntax.PropertyDeclaration è un elenco di attributi che si applicano all'attributo. Come tutti gli elementi Syntax, è costruito utilizzando un metodo factory sulla classe statica SyntaxFactory.

Roslyn Quoter può essere utile per capire come generare la sintassi utilizzando Roslyn.

In vostra particolare esempio, il metodo VisitPropertyDeclaration del vostro masterizzatore dovrebbe essere simile:

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; 
}  
+0

Che ho notato, ma non ho potuto capire come inizializzarlo, quindi la domanda. – bloudraak

+0

Vedi risposta aggiornata. –

+0

Proprio quello che stavo cercando. Grazie. – bloudraak

Problemi correlati