dotnet-script和CSI等工具允许用户像“脚本”一样编写、编译和运行 C#,而不是将他们的代码包含在完整的预编译项目中。这些工具非常适合命令行使用,但在将动态 C#“脚本”集成到更大的 C# 应用程序方面并没有提供太多帮助。
如果我有一个现有的 C# 应用程序希望通过 .csx“脚本”将其他类加载到其现有的命名空间中,我该怎么做?可能吗?
dotnet-script和CSI等工具允许用户像“脚本”一样编写、编译和运行 C#,而不是将他们的代码包含在完整的预编译项目中。这些工具非常适合命令行使用,但在将动态 C#“脚本”集成到更大的 C# 应用程序方面并没有提供太多帮助。
如果我有一个现有的 C# 应用程序希望通过 .csx“脚本”将其他类加载到其现有的命名空间中,我该怎么做?可能吗?
我猜你需要编译和执行你的 C# 脚本。
根据我的经验,我通过直接引用Microsoft.CodeAnalysis.CSharp.Scripting
(版本 3.*)来使用 C# 脚本。
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="3.*" />
我建议使用默认编译选项:
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Scripting;
// ...
ScriptOptions options = ScriptOptions.Default;
也许将来,您需要将引用的程序集添加到您的脚本编译中。
所以你需要编译你的script
(包含在下面代码中的字符串变量中):
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
显然,您需要一个入口点来执行您的脚本。我发现了这个棘手的解决方案。有用。
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();
}
我希望它可以帮助。