C# / .NETDevOpsMisc
C# / .NET
Compiling code on the fly in C#
Alexandru Puiu
Alexandru Puiu
September 24, 2012
1 min

Compile and run code created on the fly from a string or file.

Compiler c = new Compiler();
StreamReader reader = new StreamReader(/*Path to my source file, optional*/);
string compilationsource = reader.ReadToEnd(); //read from file or create on-the-fly
CodeContainer result = new CodeContainer();
result.CompiledAssembly = c.Compile(compilationsource);
result.SourceCode = compilationsource;
result.Execute("MyMethod", new object[] { MyClass }); //Send in any parameters you need

A lot more functionality than presented above is possible. To make this possible, you’ll need the following Compiler class

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Collections.Generic;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.Text;
using System.Reflection;
using System.Diagnostics;
using System.Security.Policy;
using System.IO;
using System.Web;
namespace MyNamespace
{
    ///
    /// Summary description for Compiler
    /// 
    public class Compiler
    {
        #region Properties
        private CompilerErrorCollection compilerErrors = null;
        public CompilerErrorCollection Errors
        {
            get { return compilerErrors; }
        }
        private List assemblyReferences = new List();
        public List AssemblyReferences
        {
            get { return assemblyReferences; }
            set { assemblyReferences = value; }
        }
        #endregion
        #region Constructor
        public Compiler()
        {
            compilerErrors = new CompilerErrorCollection();
        }
        #endregion
        #region Compile
        public System.Reflection.Assembly Compile(string sourceCode)
        {
            CodeDomProvider provider = CodeDomProvider.CreateProvider("csharp");
            CompilerParameters parameters = new CompilerParameters();
            CompilerResults results = null;
            StringBuilder sb = new StringBuilder();
            try
            {
                parameters.OutputAssembly = "Compiler";
                parameters.ReferencedAssemblies.Add("system.dll");
                parameters.ReferencedAssemblies.Add("mscorlib.dll");
                parameters.ReferencedAssemblies.Add("system.xml.dll");
                parameters.ReferencedAssemblies.Add("system.data.dll");
                parameters.ReferencedAssemblies.Add("system.web.dll");
                parameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");
                parameters.ReferencedAssemblies.Add("DbLib.dll");
                foreach (string reference in AssemblyReferences)
                    parameters.ReferencedAssemblies.Add(reference);
                parameters.CompilerOptions = "/t:library";
                parameters.GenerateInMemory = true;
                parameters.GenerateExecutable = false;
                parameters.IncludeDebugInformation = false;
                sb.Append(sourceCode);
                results = provider.CompileAssemblyFromSource(parameters, sb.ToString());
                if (results.Errors.Count != 0)
                {
                    compilerErrors = results.Errors;
                    throw new Exception("Code compilation errors occurred.");
                }
                else
                {
                    return results.CompiledAssembly;
                }
            }
            catch (Exception) { throw; }
        }
        #endregion
    }
    ///
    /// code container
    /// 
    public class CodeContainer
    {
        #region Properties
        public static List CodeContainers = new List();
        private string sourceCode;
        public string SourceCode
        {
            get { return sourceCode; }
            set { sourceCode = value; }
        }
        private string uniqueKey;
        public string UniqueKey
        {
            get { uniqueKey = uniqueKey ?? Guid.NewGuid().ToString(); return uniqueKey; }
            set { uniqueKey = value; }
        }
        private string nameSpace;
        public string NameSpace
        {
            get
            {
                if (nameSpace == null && SourceCode != null)
                    nameSpace = util.FirstMatch(SourceCode, @"namespaces+(w+)s?");
                return nameSpace;
            }
            set { nameSpace = value; }
        }
        private string className;
        public string ClassName
        {
            get
            {
                if (className == null && SourceCode != null)
                    className = util.FirstMatch(SourceCode, @"classs+(w+)s?");
                return className;
            }
            set { className = value; }
        }
        private System.Reflection.Assembly compiledAssembly = null;
        public System.Reflection.Assembly CompiledAssembly
        {
            get { return compiledAssembly; }
            set { compiledAssembly = value; }
        }
        private List assemblyReferences = new List();
        public List AssemblyReferences
        {
            get { return assemblyReferences; }
            set { assemblyReferences = value; }
        }
        private CompilerErrorCollection compilerErrors = null;
        public CompilerErrorCollection Errors
        {
            get { return compilerErrors; }
        }
        #endregion
        #region Methods
        public CodeContainer AddAssemblyReference(string path)
        {
            AssemblyReferences.Add(path);
            return this;
        }
        #endregion
        #region Execute
        ///
        /// This method will execute the desired classname.method with
        /// the parameters passed in and return an object.
        /// 
        public object Execute(string methodName, object[] parameters)
        {
            if (CompiledAssembly == null)
                Update(); //compile source
            return Execute(this, methodName, parameters);
        }
        public object Execute(CodeContainer codeContainer,
                              string methodName,
                              object[] parameters)
        {
            if (codeContainer.CompiledAssembly == null)
                codeContainer.Update();
            object assemblyInstance = null;
            MethodInfo methodInformation = null;
            Type type = null;
            string qualifiedClassName = "";
            try
            {
                qualifiedClassName += codeContainer.NameSpace + ".";
                qualifiedClassName += codeContainer.ClassName;
                assemblyInstance = codeContainer.CompiledAssembly.CreateInstance(
                                                                  qualifiedClassName,
                                                                  false
                                                                  );
                type = assemblyInstance.GetType();
                methodInformation = type.GetMethod(methodName);
                return methodInformation.Invoke(assemblyInstance, parameters);
            }
            catch (Exception) { throw; }
        }
        #endregion
        #region Update
        public void Update()
        {
            CodeContainer.Update(this);
        }
        ///
        /// Manages the static List CodeContainers.
        /// Compare this code with that which is set in
        /// our static List by the UniqueKey.
        /// If not found, compile and add.
        /// If found but source code is different, delete, compile, and add.
        /// If found and source code is the same, grab reference to
        /// previously compiled assembly.
        /// The codeContainer passed in will always have its .CompiledAssembly
        /// property populated after this method (Update) is called.
        /// 
        public static void Update(CodeContainer codeContainer)
        {
            CodeContainer existingCode = null;
            Compiler compiler = null;
            System.Reflection.Assembly assembly = null;
            try
            {
                existingCode = GetCodeContainer(codeContainer.UniqueKey);
                if (existingCode != null)
                {
                    if (existingCode.SourceCode != codeContainer.SourceCode)
                    {
                        Delete(existingCode);
                        existingCode = null;
                    }
                }
                if (existingCode == null)
                {
                    compiler = new Compiler();
                    compiler.AssemblyReferences = codeContainer.AssemblyReferences;
                    assembly = compiler.Compile(codeContainer.SourceCode);
                    codeContainer.CompiledAssembly = assembly;
                    CodeContainers.Add(codeContainer);
                    return;
                }
                codeContainer.ClassName = existingCode.ClassName;
                codeContainer.NameSpace = existingCode.NameSpace;
                codeContainer.CompiledAssembly = existingCode.CompiledAssembly;
            }
            catch (Exception)
            {
                if (compiler != null)
                    codeContainer.compilerErrors = compiler.Errors;
                throw;
            }
        }
        #endregion
        #region Delete
        ///
        /// Remove this code container object from our static List.
        /// 
        public static void Delete(CodeContainer code)
        {
            try
            {
                code.CompiledAssembly = null;
                CodeContainers.Remove(code);
            }
            catch (Exception) { throw; }
        }
        #endregion
        #region Get Code Container
        ///
        /// Get a reference to the static List CodeContainer object
        /// via its UniqueKey property.
        /// 
        public static CodeContainer GetCodeContainer(string uniqueKey)
        {
            try
            {
                return CodeContainers.Find(delegate(CodeContainer record)
                             {
                                 return int.Equals(record.UniqueKey,
                                                   uniqueKey);
                             });
            }
            catch (Exception) { throw; }
        }
        #endregion
    }
}

Tags

utils
Alexandru Puiu

Alexandru Puiu

Engineer / Security Architect

Systems Engineering advocate, Software Engineer, Security Architect / Researcher, SQL/NoSQL DBA, and Certified Scrum Master with a passion for Distributed Systems, AI and IoT..

Expertise

.NET
RavenDB
Kubernetes

Social Media

githubtwitterwebsite

Related Posts

RavenDB Integration Testing
Using RavenDB in Integration Testing
December 24, 2022
2 min

Subscribe To My Newsletter

I'll only send worthwhile content I think you'll want, less than once a month, and promise to never spam or sell your information!
© 2023, All Rights Reserved.

Quick Links

Get In TouchAbout Me

Social Media