8

我想一次对 Roslyn 语法树进行几处修改,全部围绕同一代码区域

tree = tree.ReplaceNodes(oldNode, newNode).RemoveNode(toRemove);

但是,只有第一次修改成功。似乎第一个更改更改了它周围的所有节点,因此该RemoveNodes方法不再toRemove在结果树中找到。我真的,真的,不想重新做工作以toRemove在新树中重新计算,并且使用单个 SyntaxRewriter 来执行所有工作(覆盖DefaultVisit方法)非常慢。

我怎样才能做我想做的事?

4

1 回答 1

5

在我提供一些替代方案之前,您对 SyntaxRewriter “慢得离谱”的评论有点令人惊讶。当您说“慢”时,您的意思是“要编写很多代码”还是“性能非常糟糕”?这是进行多次替换的最快(执行时间)方法,并且 ReplaceNodes 和 RemoveNode 在内部都使用重写器。如果您遇到性能问题,请确保在实现 DefaultVisit 时,仅当您感兴趣的节点位于调用它的节点下时才访问子类型。简单的技巧是比较跨度并确保传递的节点的跨度与您正在处理的节点相交。

无论如何,SyntaxAnnotations 提供了一种有用的方法来在修改后定位树中的节点。您可以只创建该类型的实例,然后使用 WithAdditionalAnnotations 扩展方法将其附加到节点。您可以使用 GetAnnotatedNodesOrTokens 方法再次定位该节点。

因此,解决您的问题的一种方法是注释您的 toRemove,然后当您调用 ReplaceNodes 时,在同一个调用中执行两次替换 - 一次执行 oldNode -> newNode 替换,然后一个执行 toRemove -> toRemoveWithAnnotation 替换。然后在结果树中找到带注释的节点并调用 RemoveNode。

如果您知道 oldNode 和 toRemove 不是彼此的祖先(即它们在树的不相关部分中),另一种选择是颠倒排序。获取 toRemove 的父节点(称为 oldNodeParent)并调用 RemoveNode,这意味着您将获得更新的父节点(称为 oldNodeParentRewritten)。然后,调用 ReplaceNodes 进行两次替换:oldNode -> newNode 和 oldNodeParent -> oldNodeParentRewritten。无需注释。

于 2012-11-18T00:49:32.130 回答