Search code examples
c#csharpcodeprovider

C# Runtime Compilation with CSharpCodeProvider


I have had success using this tutorial: http://www.codeproject.com/Tips/715891/Compiling-Csharp-Code-at-Runtime to set up a framework for runtime compilation and execution of C# code. Below is the code I currently have:

public static class CodeCompiler {

public static object InterpretString(string executable) {
    string compilation_string = 
    @"
    static class RuntimeCompilationCode { 
        public static void Main() {}  
        public static object Custom() {
            /* CODE HERE */
        }
    }";

    compilation_string = compilation_string.Replace("/* CODE HERE */", executable);

    CSharpCodeProvider provider = new CSharpCodeProvider();
    CompilerParameters compiler_parameters = new CompilerParameters();

    // True - memory generation, false - external file generation
    compiler_parameters.GenerateInMemory = true;

    // True - exe file generation, false - dll file generation
    compiler_parameters.GenerateExecutable = true;

    // Compile
    CompilerResults results = provider.CompileAssemblyFromSource(compiler_parameters, compilation_string);

    // Check errors
    if (results.Errors.HasErrors) {
        StringBuilder builder = new StringBuilder();
        foreach (CompilerError error in results.Errors) {
            builder.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText));
        }
        throw new InvalidOperationException(builder.ToString());
    }

    // Execute
    Assembly assembly = results.CompiledAssembly;
    Type program = assembly.GetType("RuntimeCompilationCode");
    MethodInfo execute = program.GetMethod("Custom");
    return execute.Invoke(null, null);
}

}

I can pass a statement in the form of a string (ex. "return 2;") to InterpretString() and it will be compiled and executed as part of the Custom() function. However I am wondering if it is possible to use the same approach to execute a method that is in my original file. For instance, suppose the CodeCompiler class had another method returnsTwo() which returns the integer 2. Is there a way to call such a method by passing "CodeCompiler.returnsTwo();" or a similar string to InterpretString()?


Solution

  • Provided that the function is a static function this should not be a problem, as long as you add the appropriate reference to the compilation. I've done this short of thing on several projects.

    If the CodeCompiler is in your current executable you have to include the references in this fashion:

    string exePath = Assembly.GetExecutingAssembly().Location;
    string exeDir = Path.GetDirectoryName(exePath);
    
    AssemblyName[] assemRefs = Assembly.GetExecutingAssembly().GetReferencedAssemblies();
    List<string> references = new List<string>();
    
    foreach (AssemblyName assemblyName in assemRefs)
        references.Add(assemblyName.Name + ".dll");
    
    for (int i = 0; i < references.Count; i++)
    {
        string localName = Path.Combine(exeDir, references[i]);
    
        if (File.Exists(localName))
            references[i] = localName;
    }
    
    references.Add(exePath);
    
    CompilerParameters compiler_parameters = new CompilerParameters(references.ToArray())