如何使用Roslyn代码修复提供程序API从Document中删除SyntaxNode列表?

我正在使用SyntaxFactory.VariableDeclaration定制生成的变量声明,并根据某些条件收集了一个SyntaxNode列表。

我做了以下事情:

  1. 修改节点

     var newRoot = root.ReplaceNode(expression, newVariableDeclaration) 

    这使用newVariableDeclaration成功修改了节点。

  2. 在循环中,删除与列表中存在的节点对应的节点

     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; }