Я пытаюсь разобрать файлы сценариев C#, предоставленные пользователями через Roslyn. Давайте предположим, что конечный пользователь предоставляет такой скрипт:Roslyn - как вставить переменные объявления объявления в начало скрипта (после использования)?
using System;
return "Hello";
Я ищу общий способ, чтобы вставить несколько заявлений переменной инициализации на самом раннем месте в любом данном сценарии. Насколько я понимаю, это было бы в значительной степени после последнего использования оператора.
Для примера предположим, что мне просто нужно вставить «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.
Почему это не удается? Я не уверен, почему его попытка включить мое утверждение в директиву использования - могу ли я только добавлять узлы того же типа ?!
Может ли кто-нибудь дать мне указатель на то, как достичь этого лучше всего?
Большое спасибо!
Я не возился с Roslyn, так что это просто догадка, но это может быть так, потому что C# не разрешает объявления переменных после использования директив (такая вещь будет глобальными переменными, которые C# не поддерживает) , Поэтому, когда он анализирует эту строку, он ожидает другого использования директивы (или декларации пространства имен), но вместо этого получает объявление переменной, что ему не нравится. – Abion47
Обычно да - однако это допустимый синтаксис при анализе сценария. Поскольку я явно указал SourceCodeKind.Script в параметрах синтаксического анализа, я бы предположил, что синтаксические преобразования, действующие в соответствии с этими правилами, должны (надеюсь) работать? – Bogey