为什么SyntaxNode.ReplaceNode会更改SyntaxTree选项?

Jon*_*eet 26 c# roslyn

我正在尝试替换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
    }
}
Run Code Online (Sandbox Code Playgroud)

(输出在评论中.)

这种解决方法实际上是正确的,还是有一些不同的方式我应该替换树中的节点?

Mat*_*ren 2

当您替换树中的节点时,您会创建一个新的节点子树。本质上,这个新的子树并不包含在语法树中。然而,如果您观察过该节点上的 SyntaxTree 属性,您会联想到一个新的属性。当它执行此操作时,原始的 SyntaxTree 早已不复存在,因此不可能保留解析选项。即使有可能,保留选项也毫无意义,因为您不再拥有解析器生成的树。

Roslyn 创建此 SyntaxTree 的原因是,所有子树在技术上都包含在 SyntaxTree 实例中,以便 Roslyn 可以将诊断与其关联。如果您使用 SemanticModel 的探索性 API 来尝试绑定和获取当前不属于编译的树片段的语义信息,这非常有用。诊断报告错误及其位置,指示错误所在的树实例。

  • “即使有可能,保留选项也毫无意义,因为你不再拥有解析器生成的树。” 不过,这感觉更像是理论上的原因,而不是实际的原因。当然,说“我希望这棵树与另一棵树一样,只是改变了这个节点”并不是一种不寻常的情况。当我有更多时间时,我需要仔细阅读你的其余答案,但从根本上讲,这至少在 API 使用方面感觉*尴尬*。可能必须是这样,但在我看来,这是不幸的:( (2认同)