I have wanted to know how to compile and run code at runtime for a long time. I have now got a working solution, so it’s time to share. I might even learn a better way.
So here is the C# 2.0 code, no extra references are required.
using System;
using System.Collections.Generic;
using System.Text;
using System.CodeDom.Compiler;
using System.IO;
using Microsoft.CSharp;
using System.Reflection;
namespace DynaCode
{
class Program
{
static string[] code = {
"using System;"+
"namespace DynaCore"+
"{"+
" public class DynaCore"+
" {"+
" static public int Main(string str)"+
" {"+
" return str.Length;"+
" }"+
" }"+
"}"};
static void Main(string[] args)
{
CompileAndRun(code);
Console.ReadKey();
}
static void CompileAndRun(string[] code)
{
CompilerParameters CompilerParams = new CompilerParameters();
string outputDirectory = Directory.GetCurrentDirectory();
CompilerParams.GenerateInMemory = true;
CompilerParams.TreatWarningsAsErrors = false;
CompilerParams.GenerateExecutable = false;
CompilerParams.CompilerOptions = "/optimize";
string[] references = { "System.dll" };
CompilerParams.ReferencedAssemblies.AddRange(references);
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerResults compile = provider.CompileAssemblyFromSource(CompilerParams, code);
if (compile.Errors.HasErrors)
{
string text = "Compile error: ";
foreach (CompilerError ce in compile.Errors)
{
text += "rn" + ce.ToString();
}
throw new Exception(text);
}
//ExpoloreAssembly(compile.CompiledAssembly);
Module module = compile.CompiledAssembly.GetModules()[0];
Type mt = null;
MethodInfo methInfo = null;
if (module != null)
{
mt = module.GetType("DynaCore.DynaCore");
}
if (mt != null)
{
methInfo = mt.GetMethod("Main");
}
if (methInfo != null)
{
Console.WriteLine(methInfo.Invoke(null, new object[] { "here in dyna code" }));
}
}
static void ExpoloreAssembly(Assembly assembly)
{
Console.WriteLine("Modules in the assembly:");
foreach (Module m in assembly.GetModules())
{
Console.WriteLine("{0}", m);
foreach (Type t in m.GetTypes())
{
Console.WriteLine("t{0}", t.Name);
foreach (MethodInfo mi in t.GetMethods())
{
Console.WriteLine("tt{0}", mi.Name);
}
}
}
}
}
}
The foundation of this code was a Dynamically Compiling C# blog post for IronPython.
It took me ages to realise that the string[] that CompileAssemblyFromSource consumes is a single string for each block (file) worth of C# code, not for each line. New lines and space do not affect the compiler.
I then wasted ages finding my method to call via Invoke. I have not come up with a good solution yet. Currently my code is calling a static method, as this is what I need.
The last pain was that Invoke takes an array of objects, but it then maps the array to the method being called, so the method needs to have the signature of the items in the object array. I thought I could just handle object[] as the method input. This makes sense in hind sight, but at the time it was very painful.
Now that I have working code, and know what to Google for, I have found other posts that go into great detail, like Rick Strahl’s 2002 Dynamically executing code in .Net. I feel like I’ve been under a rock.