First, you'll need to include a few namespaces you normally wouldn't:
using System.CodeDom.Compiler;
using Microsoft.CSharp;
Next, setting up the assembly compiler:
CodeDomProvider codeProvider = new CSharpCodeProvider();
CompilerParameters compilerParameters = new CompilerParameters();
compilerParameters.GenerateExecutable = false;
compilerParameters.GenerateInMemory = true;
compilerParameters.IncludeDebugInformation = false;
compilerParameters.WarningLevel = 3;
compilerParameters.TreatWarningsAsErrors = false;
compilerParameters.CompilerOptions = "/optimize";
We're using a CSharpCodeProvider here - there are other code providers for other .NET languages.
Our compiler parameters specify that we are not generating an executable, we want to compile the assembly directly in memory, rather than to disk, and we aren't including debugging information. The warning level determines the threshold for generating compiler warnings. I'm not sure exactly what level 3 does, but it's what I've seen referenced by default. It doesn't really matter, anyway, as we also specify that we aren't treating warnings as errors. Finally, we tell the compiler to optimize.
This next bit is really the only tricky part. We need to tell the compiler what extra assemblies we want to reference. The most general method I've found so far is simply to reference all of the assemblies that our parent program references, as well as the parent assembly itself:
Assembly executingAssembly = Assembly.GetExecutingAssembly();
compilerParameters.ReferencedAssemblies.Add(executingAssembly.Location);
foreach (AssemblyName assemblyName in executingAssembly.GetReferencedAssemblies())
{
compilerParameters.ReferencedAssemblies.Add(Assembly.Load(assemblyName).Location);
}
With the setup done, compiling an assembly is easy:
string assemblyCode = "public class MyClass { ...<Code Goes Here>... }";
CompilerResults compileResults =
codeProvider.CompileAssemblyFromSource(compilerParameters, new string[] { assemblyCode });
Assembly myAssembly = compileResults.CompiledAssembly;
That's all there is to it. Note that you should also check to see if and compile errors were generated. The CompileResults class has an Errors property that holds a collection of the compile errors, if any.
To use your shiny new assembly, simply use reflection to extract your class from the assembly:
Type myType = codeAssembly.GetType("MyClass");
You'll end up with a Type you can use like any other - using Activator.CreateInstance() to create a new instance of your class, for example.