我正在尝试替换罗斯林(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)并获取当前不属于编译的树的片段的语义信息,这将很有用。诊断报告错误及其位置,表示错误所在的树实例。

10-07 23:08