代码之家  ›  专栏  ›  技术社区  ›  Junior

是否可以修改Roslyn中的语法树并运行编辑过的代码?

  •  3
  • Junior  · 技术社区  · 6 年前

    SyntaxNode 是生成的,但我无法找到执行此新代码的方法。我只找到了一个 ToString 从新的 Root 打电话给我 EvaluateAsync 使用新字符串。应该有一种方法比这更好,因为我已经编译了一段新代码。

    static void Main(string[] args)
    {
        var expression = "System.Console.WriteLine(\"Test\")";
        var compile = CSharpScript.Create<EntityRepresentation>(expression).GetCompilation();
        var root = compile.SyntaxTrees.Single().GetRoot();
    
        var descentands = root.DescendantNodes().Where(n =>
        {
            if (n is ArgumentSyntax)
                return true;
            return false;
        }).ToList();
    
        var otherRoot = root.ReplaceNodes(descentands, (n1, n2) =>
        {
            var argumentName = Argument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal("NewValue")));
            return argumentName;
        });
    
        var newCode = otherRoot.ToString();
    
        // Faz o que estou querendo, contudo não me parece a melhor maneira
        var result = CSharpScript.EvaluateAsync(newCode).Result;
    }
    
    1 回复  |  直到 6 年前
        1
  •  2
  •   Alexandru Clonțea    6 年前

    不幸的是,从语法树创建脚本对象的方法是Microsoft程序集的内部方法。

    但是,您不必编译两次—您可以只解析第一次,然后再编译第二次。

    var expression = "System.Console.WriteLine(\"Test\")";
    var origTree = CSharpSyntaxTree.ParseText(expression, 
                      CSharpParseOptions.Default.WithKind(SourceCodeKind.Script));
    var root = origTree.GetRoot();
    
    // -Snip- tree manipulation
    
    var script = CSharpScript.Create(otherRoot.ToString());
    var errors = script.Compile();
    if(errors.Any(x => x.Severity == DiagnosticSeverity.Error)) {
        throw new Exception($"Compilation errors:\n{string.Join("\n", errors.Select(x => x.GetMessage()))}");
    }
    await script.RunAsync();