2015-01-08 3 views
8

Мы пытаемся выяснить, как сгенерировать код с Roslyn. Я не говорю о чем-то вроде CSharpSyntaxTree.ParseText, который возьмет несколько строк и преобразует их в AST. Вместо этого я хотел бы построить свою модель как-то вроде этого (псевдо-код):Создание семантического кода с roslyn

  1. Создать file в качестве единицы компиляции
  2. Добавить класс MyClass в file
  3. метод Add DoSomething для MyClass
  4. Установить корпус DoSomething аналогичным образом System.Linq.Expressions

Мы недавно обнаружили Microsoft.CodeAnalysis.CSharp.SyntaxFactory, и это казалось многообещающим. Однако, очевидно, мы должны сами добавлять мелочи.

После того, как вы построили дерево с помощью SyntaxFactory.CompilationUnit() и добавили некоторые элементы назад и вперед, вывод ToFullString() - это всего лишь куча текста, который не является ни удобочитаемым, ни компилируемым (например, отсутствующие фигурные скобки). Пропустили ли мы что-то при создании текста из модели?

EDIT:

При использовании рабочих областей, вы можете установить параметры, влияющие на поведение пробельных:

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

Да, но без явного указания мелочей. У меня также есть опыт использования SDK ReSharper, который в основном имеет ту же область применения. У них * есть * есть заводы, которые не обращают внимания на мелочи, и он печатает весь сгенерированный код, чистый и компилируемый. Я перекрестил некоторые комментарии других пользователей, предлагающих использовать CodeDOM, и что Roslyn предположительно не подходит для этого, но это будет казаться самым большим сбоем никогда :) – Matthias

+0

Ну ... Roslyn, будучи компилятором, предназначен для использования кода, не производить. – i3arnon

ответ

10

Вы в основном должны добавить описание блоков, то Рослины обрабатывают мелочи для вас до тех пор, как вы используете Formatter (как вы написали)

Вот пример простого класса, который генерируется правильно без сам того, чтобы указать любой мелочи

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

Это порождает следующие сл ass definiton:

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

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

Кажется, что это хорошо.

Смежные вопросы