【问题标题】:Roslyn/CSharpScript - How to Save/Load Compilation to avoid compilation wait timeRoslyn/CSharpScript - 如何保存/加载编译以避免编译等待时间
【发布时间】:2017-01-20 20:43:47
【问题描述】:

我正在尝试将 c# 脚本集成到我的数据库应用程序中。我正在使用 globals 对象来使脚本可以访问全局变量。

如果脚本是第一次编译,我对等待时间不满意。
如何保存和加载编译以避免等待时间?

Script<object> script = CSharpScript.Create(scriptCode, globalsType: typeof(MyGlobals));
script.Compile();   //<-- load the Compilation from database/file here
script.RunAsync(myGlobalsInstance).Wait();

【问题讨论】:

  • 你应该编译一个普通的程序集而不是一个脚本。
  • 关于如何手动创建编译的信息是here

标签: c# scripting roslyn


【解决方案1】:

如果要预编译,可以使用 System.CodeDom.Compiler 中的类;

CompilerParameters opts = new CompilerParameters();

opts.OutputAssembly = <Destination FileName>;
opts.ReferencedAssemblies.AddRange(<needed references>);
//set other options;            

var codeProvider = new Microsoft.CSharp.CSharpCodeProvider();
var results = codeProvider.CompileAssemblyFromFile(opts, <Your script source files>);
//check that there's no errors in the results.Errors

现在您在磁盘上有一个编译好的程序集。您可以动态加载它,从中实例化一个类并执行方法。您应该设计在接受某些配置的脚本中运行的代码。您应该采取以下步骤:

var mydll =  AppDomain.CurrentDomain.Load(<compiled Assembly From the previous step>);
    var classInstance =  <YouTypeOrInterface>mydll.CreateInstance(
      <TypeFromTheAssembly>, 
      false, 
      BindingFlags.CreateInstance, 
      null,                                                                
      new object[] { <Arguments you need to provides to your class constructor> },                                                                              CultureInfo.InvariantCulture, null);

现在你可以用这个实例做你想做的事了。例如。 classInstance.ExecuteSomething(...)

【讨论】:

  • 请注意,C# 脚本与普通 C# 不同,因此尝试使用 CodeDOM 编译脚本可能行不通,需要更改脚本。另外,如果你这样做,我看不出有任何理由使用 CodeDOM 代替 Roslyn,它也可以编译程序集。
【解决方案2】:

您可以创建一个CSharpScript,然后通过GetCompilation获取编译。

var script = CSharpScript.Create("script..");
var compilation = script.GetCompilation();

从编译中,你实际上可以将compilation.Emit() dll 和pdb 放到磁盘或内存中。棘手的(和 roslyn 内部位)是如何让代码的委托执行,一旦你有了程序集。你可以看看 roslyn 是怎么做到的here

【讨论】:

  • 好的,所以我可以将程序集发送到流媒体。但如果我理解正确,没有(简单的)方法可以将编译数据加载回 CSharpScript?
  • 如果您有程序集 (.dll),为什么还需要 CSharpScript?您加载它 (Assembly.Load),创建类型 (Activator.CreateType),然后创建要执行的委托。
  • AFAIK 一个 c# 脚本没有入口点,在我的情况下,它应该可以直接访问“globals”变量的成员。也就是说,我想从流中重新加载,我不知道该怎么做。
  • 当您在磁盘/内存上拥有程序集时,您可以像@SegeyL 的回答的第二部分中建议的那样执行脚本
  • 我找到了解决方案here
猜你喜欢
  • 2014-11-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多