2015-01-08 51 views
8

我們試圖弄清楚如何使用Roslyn生成代碼。我不是在談論像CSharpSyntaxTree.ParseText這樣的東西,它需要一些字符串並將它們轉換爲AST。相反,我想以某種方式建立自己的模型是這樣的(僞代碼):使用roslyn生成語義代碼

  1. 創建file作爲編譯單元
  2. 添加類MyClassfile
  3. Add方法DoSomethingMyClass
  4. 集體DoSomething以類似的方式如System.Linq.Expressions

我們最近發現Microsoft.CodeAnalysis.CSharp.SyntaxFactory,它似乎很有希望。但是,顯然我們必須自己添加瑣事。

在與SyntaxFactory.CompilationUnit()構建樹並來回添加一些成員之後,ToFullString()的輸出只是一堆文本,既不可讀也不可編譯(例如,缺少大括號)。從模型生成文本時,我們會錯過什麼嗎?

編輯:影響空白行爲

當使用工作區,你可以設置選項:

public string Generate (CompilationNode rootNode) 
{ 
    var cw = new CustomWorkspace(); 
    cw.Options.WithChangedOption (CSharpFormattingOptions.IndentBraces, true); 
    var formattedCode = Formatter.Format (CreateFile(rootNode), cw); 
    return formattedCode.ToFullString(); 
} 

這已經得到了較好的效果。有人可以證實這是一個很好的解決方案,或者它是一個黑客?

還有一個問題。我們想要生成一個自動屬性,目前使用的是SF.AccessorDeclaration,但是在轉換爲完整字符串時會丟失分號。

+0

你的目標是發出代碼,對吧?不編譯它? – i3arnon

+0

是的,但沒有明確指定瑣事。我也有使用ReSharper SDK的經驗,它基本上具有相同的應用領域。他們*有*工廠不知道瑣事,它確實打印所有生成的代碼清潔和可編譯。我跨過了一些其他用戶提出的建議使用CodeDOM的評論,並認爲Roslyn本來不適合這個,但這看起來像是有史以來最大的失敗:) – Matthias

+0

好吧......作爲編譯器的Roslyn是爲了消費代碼,不生產它。 – i3arnon

回答

10

你基本上要加塊定義,然後羅斯林只要您使用格式化程序(如您已寫入)

以下是一個正確生成沒有一個簡單的類的實例爲您處理瑣事我不必指定任何瑣事

var consoleWriteLine = Syntax.MemberAccessExpression(
     SyntaxKind.SimpleMemberAccessExpression, 
     Syntax.IdentifierName("Console"), 
     name: Syntax.IdentifierName("WriteLine")); 

    var arguments = Syntax.ArgumentList (
     Syntax.SeparatedList (
      new[] 
      { 
       Syntax.Argument (
        Syntax.LiteralExpression (
         SyntaxKind.StringLiteralExpression, 
         Syntax.Literal (@"""Goodbye everyone!""", "Goodbye everyone!"))) 
      })); 

    var consoleWriteLineStatement = Syntax.ExpressionStatement (Syntax.InvocationExpression (consoleWriteLine, arguments)); 

    var voidType = Syntax.ParseTypeName ("void"); 
    var method = Syntax.MethodDeclaration (voidType, "Method").WithBody (Syntax.Block(consoleWriteLineStatement)); 

    var intType = Syntax.ParseTypeName ("int"); 
    var getterBody = Syntax.ReturnStatement (Syntax.DefaultExpression (intType)); 
    var getter = Syntax.AccessorDeclaration (SyntaxKind.GetAccessorDeclaration, Syntax.Block (getterBody)); 
    var property = Syntax.PropertyDeclaration (intType, "Property").WithAccessorList (Syntax.AccessorList (Syntax.SingletonList (getter))); 

    var @class = Syntax.ClassDeclaration ("MyClass").WithMembers (Syntax.List (new MemberDeclarationSyntax[] { method, property })); 

    var cw = new CustomWorkspace(); 
    cw.Options.WithChangedOption (CSharpFormattingOptions.IndentBraces, true); 
    var formattedCode = Formatter.Format (@class, cw); 

    Console.WriteLine (formattedCode.ToFullString()); 

注:語法= Microsoft.CodeAnalysis.CSharp.SyntaxFactory

這將生成以下CL屁股定義:

class MyClass 
{ 
    void Method() 
    { 
     Console.WriteLine("Goodbye everyone!"); 
    } 

    int Property 
    { 
     get 
     { 
      return default(int); 
     } 
    } 
} 

似乎很好。