我正在尝试替换罗斯林(Roslyn)语法树中的节点,它只是可以正常工作,但是让人感到烦恼的是,这应该不成问题。
语法树是从脚本生成的,我也希望结果也是基于脚本的语法树-但由于某种原因,替换树中的节点会创建具有更改选项的新语法树:Kind
变为Regular
而不是Script
。这可以通过SyntaxTree.WithRootAndOptions
修复,但是感觉好像我做错了如果需要调用它。
示例程序:
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Scripting;
using System;
using System.Linq;
class Program
{
static void Main(string[] args)
{
Script script = CSharpScript.Create("Console.WriteLine(\"Before\")",
ScriptOptions.Default.AddImports("System"));
var compilation = script.GetCompilation();
var tree = compilation.SyntaxTrees.Single();
var after = SyntaxFactory.LiteralExpression(
SyntaxKind.StringLiteralExpression,
SyntaxFactory.Literal("After"));
var root = tree.GetRoot();
var before = root.DescendantNodes().OfType<LiteralExpressionSyntax>().Single();
var newRoot = root.ReplaceNode(before, after);
var fixedTree = newRoot.SyntaxTree.WithRootAndOptions(newRoot, tree.Options);
Console.WriteLine(newRoot); // Console.WriteLine("After")
Console.WriteLine(tree.Options.Kind); // Script
Console.WriteLine(newRoot.SyntaxTree.Options.Kind); // Regular
Console.WriteLine(fixedTree.Options.Kind); // Script
}
}
(输出在注释中。)
该解决方法实际上是否正确,还是应该用其他方法替换树中的节点?
最佳答案
替换树中的节点时,将创建节点的新子树。本质上,此新子树不包含在SyntaxTree中。但是,如果您观察到该节点上的SyntaxTree属性,就会产生一个新的属性。在执行此操作时,原始的SyntaxTree已经消失了,因此无法保留解析选项。即使有可能,保留选项也没有意义,因为解析器不再生成树。
Roslyn创建此SyntaxTree的原因是,因此所有子树在技术上都包含在SyntaxTree实例中,因此Roslyn可以将诊断与之关联。如果您使用SemanticModel的探索性API尝试绑定(bind)并获取当前不属于编译的树的片段的语义信息,这将很有用。诊断报告错误及其位置,表示错误所在的树实例。