Tools like dotnet-script and CSI allow users to write, compile, and run C# like "scripts" rather than including their code in a complete pre-compiled project. These tools work great for command-line usage, but don't offer much in terms of integrating dynamic C# "scripts" into a larger C# application.
If I have an existing C# application which wishes to load additional classes into its existing namespaces via.csx "scripts", how do I do that? Is it possible?
I guess you need to compile and execute your C# script.
In my experience, I used C# scripts by referencing Microsoft.CodeAnalysis.CSharp.Scripting
(version 3.*) directly.
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="3.*" />
I suggest to use default compilation options:
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Scripting;
// ...
ScriptOptions options = ScriptOptions.Default;
Maybe in the future, you'll need to add referenced assemblies to your script compilation.
So you need to compile your script
(contained in a string variable in the code below):
byte[] assemblyBinaryContent;
var roslynScript = CSharpScript.Create(script, options);
var compilation = roslynScript.GetCompilation();
compilation = compilation.WithOptions(compilation.Options
.WithOptimizationLevel(OptimizationLevel.Release)
.WithOutputKind(OutputKind.DynamicallyLinkedLibrary));
using (var assemblyStream = new MemoryStream())
{
var result = compilation.Emit(assemblyStream);
if (!result.Success)
{
var errors = string.Join(Environment.NewLine, result.Diagnostics.Select(x => x));
throw new Exception("Compilation errors: " + Environment.NewLine + errors);
}
assemblyBinaryContent = assemblyStream.ToArray();
}
GC.Collect(); // it allows to force clear compilation stuff.
Assembly assembly = Assembly.Load(assemblyBinaryContent);
var ret = Run(assembly); // see next paragraph
Obviously you need an entry point to execute your script. I found out this trickly solution. It works.
private object Run(Assembly assembly)
{
//Execute the script
var type = assembly.GetType("Submission#0");
var method = type.GetMethod("<Factory>", BindingFlags.Static | BindingFlags.Public);
var retTask = method.Invoke(null, new object[] { new object[2] }) as Task<object>;
return retTask.GetAwaiter().GetResult();
}
I hope it can help.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.