罗斯林 If 语句
Roslyn IfStatement
我正在使用 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'类型的异常,但未在用户代码中处理
附加信息:指定的项目不是列表的元素。
我必须使用生成器吗?我错过了什么?
谢谢
我认为这里的问题是您从 statement
创建了一棵新树,然后尝试使用该新树的一部分与 statement
进行比较。
基本上这条线第二次没有做任何事情:
blockNode = blockNode.InsertNodesBefore(newRSS, newExitCode);
blockNode
是您创建的全新树,不包含 newRSS
。所以它找不到 newRss
并插入你的 newExitCode
.
newRss
来自 block
block
来自 elseBlock
elseBlock
来自原文statement
尝试一次对语法树应用多个更改时,您可以选择三个选项:
- 使用
DocumentEditor
- See:
- 使用
Annotations
(第 235 和 239 行)
- 使用
.TrackNodes()
我的理解是 DocumentEditor
是最简单的选项,它会在幕后为您处理 tracking/annotating 节点。
这是我解决问题的方法。我使用 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 帮助解决这个问题。
我正在使用 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'类型的异常,但未在用户代码中处理
附加信息:指定的项目不是列表的元素。
我必须使用生成器吗?我错过了什么?
谢谢
我认为这里的问题是您从 statement
创建了一棵新树,然后尝试使用该新树的一部分与 statement
进行比较。
基本上这条线第二次没有做任何事情:
blockNode = blockNode.InsertNodesBefore(newRSS, newExitCode);
blockNode
是您创建的全新树,不包含 newRSS
。所以它找不到 newRss
并插入你的 newExitCode
.
newRss
来自block
block
来自elseBlock
elseBlock
来自原文statement
尝试一次对语法树应用多个更改时,您可以选择三个选项:
- 使用
DocumentEditor
- See: - 使用
Annotations
(第 235 和 239 行) - 使用
.TrackNodes()
我的理解是 DocumentEditor
是最简单的选项,它会在幕后为您处理 tracking/annotating 节点。
这是我解决问题的方法。我使用 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 帮助解决这个问题。