【发布时间】:2016-12-10 19:33:19
【问题描述】:
我的目标是解析用户通过 Roslyn 提供的 C# 脚本文件。 假设最终用户提供了如下脚本:
using System;
return "Hello";
我正在寻找一种通用方法,以便在任何给定脚本的最早可能位置插入一些变量初始化语句。 据我了解,这几乎是在最后一个 using 语句之后。
为了这个例子,假设我只需要插入“var xyz = 123;”在最早的位置。因此,在这种情况下,最终结果应该是
using System;
var xyz = 123;
return "Hello";
我该怎么做?
我尝试了以下方法;
Solution solution = new AdhocWorkspace().CurrentSolution;
var project = solution.AddProject("projectName", "assemblyName", LanguageNames.CSharp)
.WithMetadataReferences(new[] {MetadataReference.CreateFromFile(typeof(object).Assembly.Location) })
.WithParseOptions(new CSharpParseOptions(kind: Microsoft.CodeAnalysis.SourceCodeKind.Script));
// scriptCode contains the user script input, e.g.:
// using System;
// return "Hello";
Document document = project.AddDocument("SCRIPT-TEMP-DOCUMENT.cs", scriptCode);
var root = document.GetSyntaxRootAsync().Result;
var my_statement = SyntaxFactory.ParseStatement("var xyz = 123;");
// will return the node: "using System;"
var last_using = root.DescendantNodes().Where(x => x is UsingDirectiveSyntax).Last();
var documentEditor = DocumentEditor.CreateAsync(document).Result;
documentEditor.InsertAfter(last_using, my_statement);
// This step will throw an exception:
// An exception of type 'System.InvalidCastException' occurred in System.Core.dll but was not handled in user code
// non-English message, so losely translated --> Additional information: object of type "Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax" cannot be converted to "Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax"
var newDocument = documentEditor.GetChangedDocument();
当我尝试直接替换时出现同样的问题
root.InsertNodesAfter(last_using, my_statement);
而不是 DocumentEditor。
为什么会失败?我不确定为什么它试图将我的语句转换为 using 指令 - 我只能附加相同类型的节点吗?!
谁能告诉我如何做到最好?
非常感谢!
【问题讨论】:
-
我没有和 Roslyn 搞过,所以这只是一个猜测,但可能是因为 C# 不允许在使用指令后声明变量(这样的东西是全局变量,C#不支持)。因此,当它解析该行时,它期待另一个 using 指令(或命名空间声明),但却得到一个它不喜欢的变量声明。
-
通常是的 - 但是当解析为脚本时这是有效的语法。由于我在项目解析选项中明确指定了 SourceCodeKind.Script,我会假设在这些规则下有效的语法转换应该(希望)有效?
标签: c# refactoring roslyn