Roslyn IfStatement

时间:2015-06-23 20:13:25

标签: c# roslyn

我使用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();

例外是:类型&#39; System.InvalidOperationException&#39;发生在Microsoft.CodeAnalysis.CSharp.dll但未在用户代码中处理

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

我必须使用发电机吗?我错过了什么?

由于

2 个答案:

答案 0 :(得分:6)

我认为这里的问题是您从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()
  4. 我的理解是DocumentEditor是最简单的选项,并负责在封面下为您跟踪/注释节点。

答案 1 :(得分:1)

以下是我解决问题的方法。我使用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帮助他们解决这个问题。