我正在尝试使用Roslyn合并两个C#文件内容。我需要用旧版本替换旧版本中的某些方法(标记为更新)。 我遍历了两个文档中的所有成员,并将需要更改的方法标记为列表。
class Token
{
public string Name; // unique identifier
public SyntaxNode Node; // actual node in the document
}
现在我有两个令牌列表,即OldTokens和NewTokens。我需要用相应的新方法覆盖旧方法。
foreach (Token oldt in OldTokens)
{
Token newt = NewTokens.Find(m => m.Name == oldt.Name);
if (newt != null)
{
DocumentRoot = DocumentRoot.ReplaceNode(oldt.Node, newt.Node);
}
}
没用。我认为这可能是因为DocumentRoot没有将旧节点保存在其直接成员列表中,因为它将显示在namespace-> class->成员的层次结构内部。 所以我尝试了类似的东西:
var nd = existing.Node.Parent.ReplaceNode(existing.Node, miss.Node);
var d2 = existing.Node.Parent.Parent.ReplaceNode(existing.Node.Parent, nd);
DocumentRoot = existing.Node.Parent.Parent.Parent.ReplaceNode(existing.Node.Parent.Parent, d2) as CompilationUnitSyntax;
哪个有效但很难处理。当存在嵌套类时,它会变得一团糟。还有更好的方法吗?
其次,在结果中,我错过了代码注释。我尝试使用ReplaceNode方法的重载,这非常令人困惑,因为它不会占用新的方法节点。
由于
答案 0 :(得分:1)
由于Roslyn SyntaxNode
对象是不可变的,每次调用" ReplaceNode"时,都会得到一个全新的树。解决此问题的常用方法是向要替换的每个节点添加SyntaxAnnotation
。这是一个稳定的标记,只要节点本身不被替换,它将通过树转换保留。
或者,当对这样的文件进行许多更改时,您可以查看实现SyntaxRewriter
,而不是仅仅多次调用ReplaceNode
。 SyntaxRewriter
将自下而上访问树,因此传递给方法的节点将始终来自原始SyntaxTree
。但是,请确保首先在您覆盖的任何方法中调用base.Visit()
并使用结果,以便您拥有作为当前节点后代的任何节点的更新版本。
最后,关于评论,您需要从要替换的节点中复制琐事(GetLeadingTrivia()
/ GetTrailingTrivia()
),以便保留它。