Saturday, July 5, 2014

Dynamic C# code compilation

The ability to compile C# source code at runtime is a very useful technique that seems to be overlooked by a lot of .NET developers. It's a surprisingly easy way to add "scripting" abilities to your apps. I decided it was worth investigating while writing the HashStrings application which has to perform a dozen slightly different maths calculations and I wanted to be able to change them without the tedium of recompiling the project each time.

I have created a small example Visual Studio 2015 solution that shows how to dynamically compile a file of C# source code into an in-memory assembly, create and instance of a Type in that assembly and call one of its methods. The full project and source is available in this repository:

https://dev.azure.com/orthogonal/CsCompile

An interesting trick in the project is to define the symbol ORDINARY which causes the project and source to compile in the simple traditional way. Without the symbol dynamic compilation takes place.

The important part of the example code is worth extracting and displaying here.

var provider = new CSharpCodeProvider();
var parameters = new CompilerParameters();
parameters.GenerateInMemory = true;
parameters.ReferencedAssemblies.Add("System.Core.dll");
parameters.GenerateExecutable = false;
parameters.CompilerOptions = "/define:ORDINARY";
string codeToCompile = File.ReadAllText(@"..\..\SourceCode\Worker.cs");
var results = provider.CompileAssemblyFromSource(parameters, codeToCompile);
if (results.Errors.HasErrors || results.Errors.HasWarnings)
{
  // Display the results.Error collection
  return;
}
Type t = results.CompiledAssembly.GetType("cscompile.Worker");
dynamic worker = Activator.CreateInstance(t);
worker.SayHello();

Don't forget though that there are other ways of generating dynamic code. See the MSDN articles titled Using Reflection Emit and Using the CodeDOM. These techniques are much more difficult but they are strongly-typed and more robust than simply feeding free form text into a compiler.

No comments:

Post a Comment