【问题标题】:Insert new expression after statement via roslyn通过 roslyn 在语句后插入新表达式
【发布时间】:2015-05-08 14:30:53
【问题描述】:

我在使用 Roslyn 向 SyntaxTree 添加表达式时遇到了一些问题。我需要实现的是: 每当我找到一个特殊的语句时,我想在该语句之后插入一个或多个表达式。

假设我想在每个写入变量“testVar”的语句之后插入语句“myVar = myVar + 1”。

所以下面的sn-p:

 a = 10;
 testVar = 50;
 a = testVar / a;
 testVar = a;

应该变成这段代码:

 a = 10;
 testVar = 50;
 myVar = myVar + 1;
 a = testVar / a;
 testVar = a;
 myVar = myVar + 1;

我当前的方法使用带有方法“SyntaxNode VisitExpressionStatement(ExpressionStatement node)”的 SyntaxVisitor。 此方法访问 SyntaxTree 中的所有表达式,并允许用它返回的 SyntaxNode 替换访问的表达式。 但是,我不想替换语句,而是在它们之后添加新的表达式,这基本上需要返回两个表达式。 我发现的唯一解决方案是使用“BlockSyntax”作为两个表达式的容器(参见代码 sn-p [0])。不幸的是,“BlockSyntax”在自身周围引入了花括号,导致以下结果:

 a = 10;
 {
     testVar = 50;
     myVar = myVar + 1;
 }
 a = testVar / a;
 {
     testVar = a;
     myVar = myVar + 1;
 }

这种方法对我来说是不可接受的,因为我不想操纵范围。 有什么方法可以在我使用 Roslyn 选择的位置插入任意表达式?

[0]

public SyntaxNode VisitExpressionStatement(ExpressionStatement node){
    if(node has special characteristics){
        var newExpression = ...

        var newStatmentList = new Roslyn.Compilers.CSharp.SyntaxList<StatementSyntax>();
        newStatmentList = newStatmentList.Insert(newStatmentList.Count, node);
        newStatmentList = newStatmentList.Insert(newStatmentList.Count, newExpression);

        BlockSyntax newBlock = Syntax.Block(newStatmentList);
        return newBlock;

    }
    else {
        return node;
    }
}

【问题讨论】:

    标签: c# roslyn


    【解决方案1】:

    我的策略是欺骗BlockSyntax。见我的similar question

    所以我像你一样添加BlockSyntax,然后我通过将{} 标记为缺失来“删除”它们。我还没有遇到这种方法的任何问题,但它似乎更像是一种解决方法而不是解决方案。

    var statements = new SyntaxList<StatementSyntax>();
    //Tried bundling newNode and invocation together
    statements.Add(SyntaxFactory.ExpressionStatement(newNode));
    statements.Add(SyntaxFactory.ExpressionStatement(invocation));
    var wrapper = SyntaxFactory.Block(statements);
    
    //Now we can remove the { and } braces
    wrapper = wrapper.WithOpenBraceToken(SyntaxFactory.MissingToken(SyntaxKind.OpenBraceToken))
    .WithCloseBraceToken(SyntaxFactory.MissingToken(SyntaxKind.CloseBraceToken));
    

    请注意,我说我正在“删除”它们。这里的问题是,您将生成的 SyntaxTree 仍然会出现在 C# 编译器中,就好像它在您放置它的位置有一个 BlockSyntax。这可能很重要,也可能无关紧要。

    例如:

    • 如果您将此树作为字符串输出到文件中,那就没问题了。

    • 如果您立即编译这棵树,我相信编译器会将 BlockSyntax 解释为存在于您重写它的位置,并且所有范围语义仍将被强制执行,就好像它在那里一样。

    有关生成“怪异”树的更多信息,请查看我的博文:Don't Trust SyntaxNode.ToFullString()

    【讨论】:

      猜你喜欢
      • 2023-03-31
      • 2023-01-17
      • 2014-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多