2012-07-05 29 views
11

Tôi đang cố gắng tìm hiểu Roslyn bằng cách xây dựng một ứng dụng hiện có nhưng đơn giản từ đầu, có vẻ là một cách hiệu quả để tìm hiểu điều này. Nhưng dù sao, tôi có đoạn mã sau:Thêm thuộc tính được tự động triển khai vào lớp bằng cách sử dụng 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); 

Đầu ra mã sau trong ID tài liệu.

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

Mặc dù nó sẽ trông như thế này (chú ý tôi đã cố gắng thêm thuộc tính Hẹn giờ)

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

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

Ngoài ra, dường như đoạn code tôi đang viết cho một quá trình đơn giản như vậy dường như quá mức. Ngoài câu hỏi chính của tôi, mọi người có thể đưa ra đề xuất về cách tôi có thể thực hiện điều này một cách thanh lịch hơn không? Có thể một liên kết đến một blog, hoặc đoạn mã hoặc một cái gì đó?


Nó chỉ ra rằng tôi cần phải thay đổi dòng này:

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

Để dòng này:

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

Tuy nhiên, bây giờ tôi nhận được kết quả này:

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

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

Bây giờ tôi không nhận được "get; set;" văn bản trong thuộc tính. Có ai biết tôi đang thiếu gì không?

Trả lời

7

Tôi nghĩ lý do tại sao bất động sản không được thêm là SyntaxList s, giống như mọi thứ khác trong Roslyn, không thay đổi. Không Add() trả lại cập nhật SyntaxList? (Tôi không thể xác minh điều này ngay bây giờ, tôi chưa chuyển sang CTP mới.)

Và mã như thế này trong Roslyn có thể rất tiết, nhưng bạn đang làm cho nó phức tạp hơn cần thiết. Bạn không cần phải cập nhật root sau mỗi thay đổi, nếu bạn xây dựng cây cú pháp từ dưới lên: trước tiên hãy tạo các thành viên của lớp, sau đó là lớp, sau đó là vùng tên. Nếu bạn làm điều đó, bạn sẽ không phải đối phó với tất cả các chú thích.

+0

Lời nhắc của bạn về tính bất biến dẫn tôi nhận ra những gì tôi đã làm sai mà tôi đăng tải dưới đây. Tôi sẽ hỏi một câu hỏi riêng về cách thực sự xây dựng cây cú pháp cụ thể của tôi từ dưới lên. – Beaker

+0

Đây là liên kết đến câu hỏi mới của tôi về cách tôi xây dựng Cây Cú pháp của tôi từ đầu khi bạn đề xuất. http://stackoverflow.com/questions/11351977/roslyn-ctp-building-a-syntaxtree-from-the-ground-up – Beaker

+1

Trong câu hỏi khác của bạn, tôi đã thêm một liên kết đến một công cụ có tên Quoter có thể giúp tự động tạo các cuộc gọi API cú pháp Roslyn cho bất kỳ chương trình nào: http://blogs.msdn.com/b/kirillosenkov/archive/2012/07/22/roslyn-code-quoter-tool-generating-syntax-tree-api- calls-for-any-c-program.aspx –

5

Sử dụng API thông thạo mới (.Với ...() phương pháp) bây giờ bạn có thể sử dụng:

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))))); 
Các vấn đề liên quan