I was having trouble with performance when using Roslyn to compile to a dynamic assembly. Compilation was taking ~3 seconds, compared to ~300 milliseconds to compile the same code when using the CodeDom
compiler. Here's a pared-down version of the code I'm using to do the compilation:
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());
}
This answer suggests passing a ModuleBuilder object into the Emit method instead of a MemoryStream in order to speed things up. I tried to follow that pattern, like so:
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());
But my version of Roslyn apparently doesn't have an overload of the Emit
method that takes a ModuleBuilder
. That version is:
Id: Microsoft.CodeAnalysis
Version: 0.6.4033103-beta (Prerelease)
Project Information: http://msdn.microsoft.com/en-US/roslyn
Obviously, this is a prerelease, so it's not strange that the api might have changed. However,
My Question(s)
- Does anyone know why the
Emit
method no longer seems to have an overload that takes aModuleBuilder
? - Is there another way to make this compilation faster while still using Roslyn (Roslyn offers a couple advantages over the
CodeDom
and Mono compilers that I'd prefer not to give up)?
Roslyn currently doesn't expose ability to emit dynamic assemblies. We removed it because it was problematic.
You can still emit to a
MemoryStream
usingCompilation.Emit
APIs and then useAssembly.Load(byte[])
to load the resulting binary.Note that this assembly won't be freed until the containing
AppDomain
is unloaded.