Roslyn 在更改的文档中查找相同的节点

Roslyn Find Same Node in Changed Document

众所周知 Roslyn 语法树是不可变的,因此在进行更改后您需要获取一个新节点。

我正在尝试使用文档编辑器更新文档,但我一直收到错误消息,指出在语法树中找不到该节点。

public static T FindEquivalentNode<T>(this Document newDocument, T node)
    where T : CSharpSyntaxNode
{
    var root = newDocument.GetSyntaxRootAsync().Result;
    return root.DescendantNodes().OfType<T>()
            .FirstOrDefault(newNode => SyntaxFactory.AreEquivalent(newNode, node));
}

当我尝试再次调用文档编辑器时:

var newFieldDeclaration = documentEditor.GetChangedDocument().FindEquivalentNode(syntaxNode);
documentEditor.ReplaceNode(newFieldDeclaration, propertyDeclaration);

我收到一个错误:

The node is not part of the tree

newField Declaration is not null it find an equivalent field but I still get this error,如何替换此节点?

您获得节点是因为在您的 FindEquivalentNode 方法中,您正在这样做:

SyntaxFactory.AreEquivalent(newNode, node)

SyntaxFactory.AreEquivalent 对于 "real" 相同的节点不是 return,但是对于 nodes\tokens 它们的结构似乎相等(考虑到 topLevel参数).

回到你的问题,如果你想调用 ReplaceNode 你必须有 "real" 旧节点,所以你不会得到

The node is not part of the tree

要实现这一点,您有几个选择,其中之一是@Tamas 在评论中写的,使用 SyntaxAnnotations

示例:

//Add annotation to node 
var annotation = new SyntaxAnnotation("your_annotation", "some_data");
node = node .WithAdditionalAnnotations(annotation);

// Now you can change the tree as much you want

// And when you want to get the node from the changed tree 
var annotatedNode = someNode.DescendantNodesAndSelf().
        FirstOrDefault(n => n.GetAnnotations("your_annotation").Any())