【问题标题】:Roslyn IfStatementRoslyn If 语句
【发布时间】:2015-09-09 19:57:58
【问题描述】:

我正在使用 Roslyn 语法树来更新 if/else 语句。这是我的代码:

foreach (StatementSyntax statement in blockNode.Statements)
{
    if (statement.IsKind(SyntaxKind.IfStatement))
    {
        BlockSyntax ifBlock = statement.ChildNodes().OfType<BlockSyntax>().FirstOrDefault();
        if (ifBlock != null)
        {
            ReturnStatementSyntax newRSS = ifBlock.ChildNodes().OfType<ReturnStatementSyntax>().FirstOrDefault();
            blockNode = blockNode.InsertNodesBefore(newRSS, newExitCode);
        }
        ElseClauseSyntax elseBlock = statement.ChildNodes().OfType<ElseClauseSyntax>().FirstOrDefault();
        if (elseBlock != null)
        {
            BlockSyntax block = elseBlock.ChildNodes().OfType<BlockSyntax>().FirstOrDefault();
            if (block != null)
            {
                ReturnStatementSyntax newRSS = block.ChildNodes().OfType<ReturnStatementSyntax>().FirstOrDefault();
                blockNode = blockNode.InsertNodesBefore(newRSS, newExitCode);
            }
        }
        newBlock = newBlock.AddRange(blockNode.Statements);
    }
}

谁能解释为什么第一个 blockNode 插入节点有效,而第二个无效?我两次都看到了我想要插入的代码,但只有第一个更新了语法树。第二个什么都不做。

更新:我已按照 JoshVarty 的建议进行了更改。我使用 DocumentEditor 来加载更改。我现在在调用 GetChangedDocument 时遇到异常。这是我的代码:

DocumentEditor editor = DocumentEditor.CreateAsync(doc).Result;
editor.InsertBefore(blockNode, newEntryCode);
editor.InsertAfter(blockNode, newExitCode);
Document newDoc = editor.GetChangedDocument();

异常是:Microsoft.CodeAnalysis.CSharp.dll 中出现“System.InvalidOperationException”类型的异常,但未在用户代码中处理

附加信息:指定的项目不是列表的元素。

我必须使用生成器吗?我错过了什么?

谢谢

【问题讨论】:

    标签: c# roslyn


    【解决方案1】:

    我认为这里的问题是您从 statement 创建了一棵新树,然后尝试使用该新树的部分内容与 statement 进行比较。

    基本上这条线第二次没有做任何事情:

    blockNode = blockNode.InsertNodesBefore(newRSS, newExitCode);
    

    blockNode 是您创建的全新树,不包含newRSS。所以它找不到newRss 并插入你的newExitCode

    • newRss 来自block
    • block 来自elseBlock
    • elseBlock 来自原来的statement

    尝试一次将多个更改应用于语法树时,您有三个选项:

    1. 使用DocumentEditor - 请参阅:https://stackoverflow.com/a/30563669/300908
    2. 使用Annotations(第 235 和 239 行)
    3. 使用.TrackNodes()

    我的理解是DocumentEditor 是最简单的选项,它会在后台为您跟踪/注释节点。

    【讨论】:

    • 另一种选择是显式使用重写器并执行一次自下而上的重写过程。
    【解决方案2】:

    这是我解决问题的方法。我使用 SyntaxGenerator 重写 if 语句,然后在重写某些方法时使用 DocumentEditor 保存对语法树的所有更改。以下是相关代码:

    SyntaxGenerator synGen = editor.Generator;
    foreach (StatementSyntax statement in blockNode.Statements)
    {
        if (statement.IsKind(SyntaxKind.IfStatement))
        {
            IfStatementSyntax ifs = statement as IfStatementSyntax;
            SyntaxList<StatementSyntax> trueStatements = new SyntaxList<StatementSyntax>();
            SyntaxList<StatementSyntax> falseStatements = new SyntaxList<StatementSyntax>();
    
            BlockSyntax ifBlock = ifs.ChildNodes().OfType<BlockSyntax>().FirstOrDefault();
            if (ifBlock != null)
            {
                ReturnStatementSyntax newRSS = ifBlock.ChildNodes().OfType<ReturnStatementSyntax>().FirstOrDefault();
                SyntaxList<StatementSyntax> ifStatements = ifBlock.Statements;
                foreach (StatementSyntax ss in ifStatements)
                {
                    if (ss.Kind() != SyntaxKind.ReturnStatement)
                    {
                        trueStatements = trueStatements.Add(ss);
                    }
                 }
                 foreach (StatementSyntax ss in newExitCode)
                 {
                     trueStatements = trueStatements.Add(ss);
                 }
                 trueStatements = trueStatements.Add(newRSS);
                 ElseClauseSyntax elseBlock = ifs.ChildNodes().OfType<ElseClauseSyntax>().FirstOrDefault();
                 if (elseBlock != null)
                 {
                     BlockSyntax block = elseBlock.ChildNodes().OfType<BlockSyntax>().FirstOrDefault();
                     if (block != null)
                     {
                         ReturnStatementSyntax newRSS = block.ChildNodes().OfType<ReturnStatementSyntax>().FirstOrDefault();
                         SyntaxList<StatementSyntax> elseStatements = block.Statements;
                         foreach (StatementSyntax ss in elseStatements)
                         {
                             if (ss.Kind() != SyntaxKind.ReturnStatement)
                             {
                                 falseStatements = falseStatements.Add(ss);
                             }
                         }
                         foreach (StatementSyntax ss in newExitCode)
                         {
                             falseStatements = falseStatements.Add(ss);
                         }
                         falseStatements = falseStatements.Add(newRSS);
                     }
                 }
                 IfStatementSyntax newIfStatement = (IfStatementSyntax)synGen.IfStatement(ifs.Condition, trueStatements, falseStatements);
                 newBlock = newBlock.Add(newIfStatement);
            }
            else
            {
                if (!statement.IsKind(SyntaxKind.ReturnStatement))
                {
                    newBlock = newBlock.Add(statement);
                }
                else
                {
                    newBlock = newBlock.AddRange(newExitCode);
                    newBlock = newBlock.Add(statement);
                }
            }
        }
    }
    var newBody = SyntaxFactory.Block(SyntaxFactory.Token(SyntaxKind.OpenBraceToken), newBlock, SyntaxFactory.Token(SyntaxKind.CloseBraceToken));
    var newMethod = SyntaxFactory.MethodDeclaration(mds.AttributeLists, mds.Modifiers, mds.ReturnType, mds.ExplicitInterfaceSpecifier, mds.Identifier, mds.TypeParameterList, mds.ParameterList, mds.ConstraintClauses, newBody, mds.ExpressionBody);
    editor.ReplaceNode(mds, newMethod);
    SyntaxNode newRoot = editor.GetChangedRoot();
    var newFormattedRoot = Formatter.Format(newRoot, Workspace);
    Document newDoc = editor.GetChangedDocument();
    doc = doc.WithSyntaxRoot(newFormattedRoot);
    methodsChanged++;
    

    感谢 Josh Varty 和 Jeroen Vannevel 协助解决这个问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-02-06
      • 2016-03-26
      • 1970-01-01
      • 2016-03-02
      • 2016-02-29
      • 1970-01-01
      • 1970-01-01
      • 2011-12-01
      相关资源
      最近更新 更多