Compiling Code at Runtime
// December 12th, 2009 // Useful Code
This little snippit has only ever been used once by me in an attempt to give the end user the ability to make adjustments to processing scripts. It turned out to be a little bit of a headache because hoping your end user has the skill and ability to code in C# or any language for that matter is a bit troublesome. Who knows though you might be able to use this as part of a Visual Studio addin which allows the user to customize the functionality to their likings. In any event on to some code.
//Class
public static class AssemblyBuilder
{
/// <summary>
/// COMPILE CODE INTO A MEMORY DLL
/// </summary>
/// <param name="Code">PLAIN TEXT OF THE CODE TO BE EXECUTED</param>
/// <returns>MEMORY DLL OF COMPILED CODE</returns>
static Assembly BuildAssembly(string Code)
{
CSharpCodeProvider tmpProvider = new CSharpCodeProvider();
CompilerParameters tmpParams = new CompilerParameters() { GenerateExecutable = false, GenerateInMemory = true };
//ADD ANY ADDITIONAL REFERENCES YOU MAY NEED HERE
tmpParams.ReferencedAssemblies.Add("System.dll");
tmpParams.ReferencedAssemblies.Add("System.Windows.Forms.dll");
//ATTEMPT TO COMPILE THE CODE INTO A MEMORY DLL
CompilerResults tmpResults = tmpProvider.CompileAssemblyFromSource(tmpParams, Code);
//IF IT WORKED THEN RETURN THE COMPILED ASSEMBLY ELSE RETURN NOTHING
if (!tmpResults.Errors.HasErrors)
return tmpResults.CompiledAssembly;
else
return null;
}
/// <summary>
/// COMPILE AND EXECUTE PLAIN TEXT AS THOUGH IT WERE A LOADED LIBRARY
/// </summary>
/// <param name="code">CODE TO COMPILE</param>
/// <param name="namespacename">NAMESPACE INSIDE THE CODE FROM WHICH TO EXECUTE</param>
/// <param name="classname">CLASS NAME INSIDE THE NAMESPACE FROM WHICH TO EXECUTE</param>
/// <param name="functionname">FUNCTION TO EXECUTE INSIDE OF THE CLASS</param>
/// <param name="isstatic">IS THE METHOD A STATIC METHOD OR AN INSTANCED METHOD</param>
/// <param name="args">ARRAY OF ARGUMENTS TO BE PASSED INTO THE FUNCTION WE ARE CALLING</param>
/// <returns>RETURNS ANY VALUE RETURNED BY THE FUNCTION THAT WAS CALLED</returns>
public static object ExecuteCode(string code, string namespacename, string classname, string functionname, bool isstatic, params object[] args)
{
Type tmpType = null;
object tmpInstance = null;
Assembly tmpAsm = BuildAssembly(code);
//CHECK TO VERIFY THE BUILDASSEMBLY WORKED
if (tmpAsm != null)
{
//IF THIS IS A STATIC METHOD WE CAN CALL IT DIRECTLY OTHERWISE WE NEED TO CREATE AN INSTANCE OF THE LIBRARY FIRST
if (isstatic)
{
tmpType = tmpAsm.GetType(namespacename + "." + classname);
}
else
{
tmpInstance = tmpAsm.CreateInstance(namespacename + "." + classname);
tmpType = tmpInstance.GetType();
}
//FIND THE METHOD WE WISH TO EXECUTE
MethodInfo method = tmpType.GetMethod(functionname);
//RETURN WHATEVER VALUE COMES BACK FROM THE FUNCTION CALL
return method.Invoke(tmpInstance, args);
}
else
{
return null;
}
}
}
//Usage
string plainTextCode = "using System.Windows.Forms;namespace Test{public class Test {public void Main(){MessageBox.Show(\"Testing!\", \"Test Title\"); }}}";
AssemblyBuilder.ExecuteCode(plainTextCode, "Test", "Test", "Main", false, new object[]{});
Michael E. Chancey Jr. Software Engineer Extraordinaire