使用roslyn生成语义代码

时间:2015-01-08 14:13:20

标签: c# roslyn

我们试图找出如何使用Roslyn生成代码。我不会谈论像CSharpSyntaxTree.ParseText这样的东西,它会占用一些字符串并将它们转换成AST。相反,我想以某种方式构建我的模型(伪代码):

  1. 创建file作为编译单元
  2. 将课程MyClass添加到file
  3. 将方法DoSomething添加到MyClass
  4. 以与DoSomething
  5. 类似的方式设置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,但在转换为完整字符串时它会错过分号。

2 个答案:

答案 0 :(得分:10)

你基本上必须添加块定义,然后只要你使用Formatter(就像你写的那样),Roslyn就会为你处理这个琐事

这是一个正确生成的简单类的示例,无需我自己指定任何琐事

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

这将生成以下类定义:

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

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

似乎很好。

答案 1 :(得分:0)

我遇到了同样的问题,发现 CustomWorkspace 现在称为 AdhocWorkspace

var cw = new AdhocWorkspace();
cw.Options.WithChangedOption(CSharpFormattingOptions.IndentBraces, true);
var formatter = Formatter.Format(cu, cw);
StringBuilder sb = new StringBuilder();
using (StringWriter writer = new StringWriter(sb))
{
    formatter.WriteTo(writer);
}
var code = sb.ToString();