2014-10-22 37 views
2

我正在根据某些条件使用SyntaxFactory.VariableDeclarationSyntaxNode收集的自定义生成变量声明。如何使用Roslyn代码修复提供程序API从文档中删除SyntaxNode列表?

我做了以下内容:

  1. 修改

    var newRoot = root.ReplaceNode(expression, newVariableDeclaration) 
    

    这成功修改了节点与newVariableDeclaration节点。

  2. 在循环中删除对应于存在于列表中的那些

    foreach (var listObject in listObjects) 
    { 
        newRoot = newRoot.RemoveNode(listObject, SyntaxRemoveOptions.KeepNoTrivia); 
    } 
    

    这并不改变newRoot和需要被改变了所有的listObject保持相同的节点。

如果我们使用root.RemoveNode(listObject, SyntaxRemoveOptions.KeepNoTrivia)相反,它会很明显,不断取代了以往的变化。

所以这里的newVariableDeclaration是在整个文档中改变的唯一节点,这是因为newRootSyntaxNodes具有不同于我从root获得SyntaxNode的变化。

请纠正我,如果我做错了。

编辑: 我看着CSharpSyntaxRewriter但现在看来,它是分析单个节点每次它访问一个节点,并只能在同一时间修改单个节点。在我的场景中,我将不得不访问特定节点,对其进行更改,并根据对访问节点所做的更改删除其他节点。

回答

1

您的方法存在的问题是,无论何时更改树(使用ReplaceNode()RemoveNode()),这意味着所有节点都会发生更改。这就是为什么ReplaceNode()之后您拨打RemoveNode()不会做任何事情的原因。

解决此问题的一种方法是使用TrackNodes(),以便您可以找到修改的树中的哪些节点与原始树中的节点相对应。

Uisng此,替换节点的序列与单个节点可能看起来像这样的方法:

public static T ReplaceNodes<T>(
    this T root, IReadOnlyList<SyntaxNode> 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; 
} 
相关问题