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[]{});
Be Sociable, Share!
  • RSS
  • Twitter
  • Facebook
  • LinkedIn
  • DeviantArt