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メソッドを使用して、ノードを再度見つけることができます。

したがって、問題に取り組む1つの方法は、toRemoveに注釈を付けることです。次に、ReplaceNodesを呼び出すときに、同じ呼び出しで2つの置換を実行します。1つはoldNode-> newNode置換を実行し、もう1つはtoRemove->toRemoveWithAnnotation置換を実行します。次に、結果のツリーで注釈付きノードを見つけて、RemoveNodeを呼び出します。

oldNodeとtoRemoveが相互の祖先ではないことがわかっている場合(つまり、ツリーの無関係な部分にある場合)、別のオプションは順序を逆にすることです。toRemoveの親ノード(oldNodeParentと呼びます)を取得し、RemoveNodeを呼び出します。つまり、更新された親ノード(oldNodeParentRewrittenと呼びます)を取得します。次に、ReplaceNodesを呼び出して、oldNode->newNodeとoldNodeParent->oldNodeParentRewrittenの2つの置換を実行します。注釈は必要ありません。

于 2012-11-18T00:49:32.130 に答える