I'm aiming to parse C# script files supplied by users via Roslyn. Let's assume the end user provides a script like:
using System;
return "Hello";
I'm looking for a general way to insert a few variable initialization statements at the earliest possible location in any given script. To my understanding, that would pretty much be after the last using statement.
For the sake of the example, let's assume I just need to insert "var xyz = 123;" at the earliest location. So the end result should, in this case, be
using System;
var xyz = 123;
return "Hello";
How could I do that?
I tried the following;
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();
Same issue when I try directly replacing with
root.InsertNodesAfter(last_using, my_statement);
instead of the DocumentEditor.
Why does this fail? I'm not sure why its trying to cast my statement into a using directive - can I only append nodes of the same type?!
Could anybody give me a pointer of how to achieve this best?
Thanks a lot!