For all those who haven't experimented with it, the Microsoft.CSharp namespace in the .NET BCL provides access to a fully functioning C# compiler. Using this it only takes a few simple steps to add powerful scripting support to any project. For those interested, I'll demonstrate the simplest way to get such a system up and running with only a few lines of code.
First we'll want access to the namespaces where all this functionality resides.
using Microsoft.CSharp;
using System.CodeDom;
using System.CodeDom.Compiler;
Next up we need to create the objects that will actually do the work of compiling our scripts for us.
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
ICodeCompiler codeCompiler = codeProvider->CreateCompiler();
With that ready, the compilation parameters need to be set up so the compile knows exactly what we want made. Most of these options are pretty straightforward and obvious. Pay close attention to the ReferencedAssemblies property of the compiler parameters however. This is where we tell the compiler which assemblies we want our script to have access to. For example, if the script is going to be doing any works with forms, it'll need to reference "System.Windows.Forms.dll."
CompilerParameters params = new CompilerParameters();
params.GenerateExecutable = false;
params.GenerateInMemory = true;
params.IncludeDebugInformation = false;
params.TreatWarningsAsErrors = false;
params.ReferencedAssemblies.Add( "System.dll" );
params.ReferencedAssemblies.Add( "System.Windows.Forms.dll" );
CompilerResults results = codeCompiler.CompileAssemblyFromFile( params, "MyScript.cs" );
At this point if the compiler met with any errors they can be found in the results.Errors member. Otherwise, we now have a new assembly loaded into memory and ready for use. Using the System.Reflection namespace, any types or methods declared in the source file can be discovered and used. Let's assume that the source file looks like the following:
// MyScript.cs
using System;
using System.Windows.Forms;
class Script
{
public static void Main()
{
MessageBox.Show( "This is a script!" );
}
}
Given that source after compilation by the preceding steps, the following will be sufficient to call the static Main method.
results.CompiledAssembly.GetType( "Script").GetMethod( "Main" ).Invoke( null, null );
Of course that only covers the basics, but there you have it.