C# 将Roslyn Emit方法与ModuleBuilder而不是MemoryStream一起使用

C# 将Roslyn Emit方法与ModuleBuilder而不是MemoryStream一起使用,c#,performance,roslyn,dynamic-assemblies,cci,C#,Performance,Roslyn,Dynamic Assemblies,Cci,在使用Roslyn编译为动态程序集时,我遇到了性能问题。编译大约需要3秒钟,而使用CodeDom编译器编译相同的代码大约需要300毫秒。下面是我用来编译的代码的精简版本: var compilation = CSharpCompilation.Create( "UserPayRules.dll", syntaxTrees,

在使用Roslyn编译为动态程序集时,我遇到了性能问题。编译大约需要3秒钟,而使用
CodeDom
编译器编译相同的代码大约需要300毫秒。下面是我用来编译的代码的精简版本:

var compilation = CSharpCompilation.Create(
                                      "UserPayRules.dll",
                                      syntaxTrees,
                                      assembliesToAdd);

using (var stream = new MemoryStream())
{
    stopWatch.Start();
    var result = compilation.Emit(stream);
    stopWatch.Stop();
    Debug.WriteLine("Compilation: {0}", stopWatch.ElapsedMilliseconds);
    if (!result.Success)
    {
        throw new InvalidOperationException();
    }
    var assembly = Assembly.Load(stream.GetBuffer());
}
建议将ModuleBuilder对象传递到Emit方法,而不是MemoryStream,以加快速度。我试着遵循这种模式,就像这样:

var compilation = CSharpCompilation.Create(
                                      "UserPayRules.dll",
                                      syntaxTrees,
                                      assembliesToAdd);

var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
                                       new AssemblyName("ThisAssembly"),
                                       AssemblyBuilderAccess.RunAndCollect);

var moduleBuilder = assemblyBuilder.DefineDynamicModule("ThisModule");
var result = compilation.Emit(moduleBuilder);

Debug.WriteLine("Compilation: {0}", stopWatch.ElapsedMilliseconds);
if (!result.Success)
{
    throw new InvalidOperationException();
}
var assembly = Assembly.Load(stream.GetBuffer());
但是我的Roslyn版本显然没有采用
ModuleBuilder
Emit
方法的重载。该版本为:

Id:Microsoft.CodeAnalysis
版本:0.6.4033103-beta(预发布)
项目信息:

显然,这是一个预发布版本,因此api可能已经更改并不奇怪。但是,

我的问题
  • 有人知道为什么
    Emit
    方法不再具有占用
    ModuleBuilder
    的重载吗
  • 在仍然使用Roslyn的情况下,有没有其他方法可以加快编译速度(Roslyn提供了一些优于
    CodeDom
    和Mono编译器的优点,我不想放弃)

  • Roslyn目前不公开发出动态程序集的功能。我们删除它是因为它有问题

    您仍然可以使用
    Compilation.emit
    API向
    MemoryStream
    发送,然后使用
    Assembly.Load(byte[])
    加载生成的二进制文件


    请注意,在卸载包含的
    AppDomain
    之前,此程序集不会被释放。

    查看,Roslyn似乎正在使用,它(除其他外)是Reflection.Emit的替代品。我想这就是为什么不支持
    ModuleBuilder
    的原因。谢谢你给CCI的链接——我不熟悉它。该网站声称它(除其他外)比Reflection.Emit更高效。我必须深入研究他们的文档,找出为什么我不是这样。你正在看CTP。永远不要评判CTP的性能。此外,“Known Issues.docx”文件声明“在启动Visual Studio后,第一次构建可能会比预期的慢,因为编译器在预览中没有被加密。”这显然适用于使用CTP的每个程序,不只是VS如果你在罗斯林团队:考虑把这个信息添加到你的个人资料中,这样你的答案就显得权威。谢谢你的解释,托马斯。您知道为了提高编译性能,有哪些地方需要查找/更改哪些选项吗?现在,与使用CodeDom相比,它非常慢。我应该对最后一条评论进行限定:它第一次运行时非常慢。第一次运行约4500毫秒,后续运行约15毫秒。相比之下,CodeDom的第一次运行约为300毫秒,后续运行约为80毫秒。由于此代码主要在App_Start上运行,因此,如果启动需要几秒钟,后续运行的速度有多快并不重要。您可能有兴趣投票支持此功能请求:@TomasMatousek您能否澄清这到底是如何“有问题”的,以及这是否在Roslyn的管道中?至少从.NET 4.0开始,Reflection.Emit就支持可收集程序集,因此对于所有希望在其应用程序中使用正确脚本的用户来说,能够将语法树编译成
    ModuleBuilder
    似乎是一个非常理想的目标。。。