如何使用Roslyn代码修复提供程序API从Document中删除SyntaxNode列表?
我正在使用SyntaxFactory.VariableDeclaration
定制生成的变量声明,并根据某些条件收集了一个SyntaxNode
列表。
我做了以下事情:
-
修改节点
var newRoot = root.ReplaceNode(expression, newVariableDeclaration)
这使用
newVariableDeclaration
成功修改了节点。 -
在循环中,删除与列表中存在的节点对应的节点
foreach (var listObject in listObjects) { newRoot = newRoot.RemoveNode(listObject, SyntaxRemoveOptions.KeepNoTrivia); }
这不会更改
listObject
需要更改的所有listObject
保持不变。
如果我们使用root.RemoveNode(listObject, SyntaxRemoveOptions.KeepNoTrivia)
它显然将继续替换先前的更改。
所以这里newVariableDeclaration
是整个文档中唯一被更改的节点,这是因为SyntaxNodes
SyntaxNode
与我从root
获取的SyntaxNode
更改。
如果我做错了,请纠正我。
编辑:我查看了CSharpSyntaxRewriter
但似乎它每次访问节点时都在分析单个节点,并且一次只能修改一个节点。 在我的场景中,我将不得不访问特定节点,对其进行更改,并删除与访问节点所做更改相关的其他节点。
您的方法的问题是无论何时更改树(使用ReplaceNode()
或RemoveNode()
),这意味着所有节点也会更改。 这就是您在RemoveNode()
之后调用ReplaceNode()
不执行任何操作的原因。
解决此问题的一种方法是使用TrackNodes()
,以便您可以找到修改后的树中哪些节点对应于原始树中的节点。
使用此方法,用单个节点替换节点序列的方法可能如下所示:
public static T ReplaceNodes( this T root, IReadOnlyList oldNodes, SyntaxNode newNode) where T : SyntaxNode { if (oldNodes.Count == 0) throw new ArgumentException(); var newRoot = root.TrackNodes(oldNodes); var first = newRoot.GetCurrentNode(oldNodes[0]); newRoot = newRoot.ReplaceNode(first, newNode); var toRemove = oldNodes.Skip(1).Select(newRoot.GetCurrentNode); newRoot = newRoot.RemoveNodes(toRemove, SyntaxRemoveOptions.KeepNoTrivia); return newRoot; }