Richard Lemmens website

Copyright:
PublicDomain
This text content and maps on this page are in the public domain. This means you are free to copy, adapt, share, distribute and even capitalize on it.

Hot C#

With the rise of .NET Core, this article is becoming somewhat outdated. It remains here for reference. For a more recent insight into compiling C# on the fly, read the ever interesting Rick Strahl: https://weblog.west-wind.com/posts/2022/Jun/07/Runtime-CSharp-Code-Compilation-Revisited-for-Roslyn

C# code is almost always compiled to Common Intermediate Language, which is then run on the .NET framework Common Language Runtime. This means that you probaly need a compiler to make your code "runnable", as C# interpreters are rare and outside the mainstream. But here is a gem: .NET has a compiler built into it!
Below is an example that shows how to write a program that compiles C# code and executes it. It calls a given method in your code, assumes that that generates output and returns that.
A small catch is that if your code references assemblies, they must be included in the assembly that executes the "CompileAndExecute" method, so that that method can pick them up from there.

           
public static CompileAndExecute(string code, string codeNamespace = "myNamespace", string codeClass = "myClass", string codeMethod, string outputAssemblyName = "tempCsharpScript")
{
    System.CodeDom.Compiler.CompilerResults compilerResults = Compile(code, codeNamespace, codeClass, outputAssemblyName);
    if (compilerResults.Errors.Count > 0)
    {
        string errors = "Compilation failed:\n" ;
        foreach (System.CodeDom.Compiler.CompilerError err in compilerResults.Errors)
        {
            errors += err.ToString() + "\n";
        }
        // Output "errors" to wherever you want it to go
        return;
    }
    object codeObject = null;
    System.Reflection.MethodInfo codeMethodInfo = null;
    try
    {
        GetHandle(compilerResults, codeNamespace, codeClass, codeMethod, out codeObject, out codeMethodInfo);
    }
    catch (System.ArgumentException aex)
    {
        // Output "aex" to wherever you want it to go
        return;
    }
    object results = await System.Threading.Tasks.Task.Run(() => codeMethodInfo.Invoke(codeObject, null));
    // Output "results" to wherever you want it to go
    if (System.IO.File.Exists(outputAssemblyName))
    {
        System.IO.File.Delete(outputAssemblyName);
    }
}
    
public static System.CodeDom.Compiler.CompilerResults Compile(string code, string codeNamespace, string codeClass, string outputAssemblyName)
{
    Microsoft.CSharp.CSharpCodeProvider compiler = new Microsoft.CSharp.CSharpCodeProvider();
    System.CodeDom.Compiler.CompilerParameters compilerParams = new System.CodeDom.Compiler.CompilerParameters();
    compilerParams.GenerateExecutable = false;
    compilerParams.GenerateInMemory = true;
    compilerParams.OutputAssembly = outputAssemblyName;
    compilerParams.MainClass = codeNamespace + "." + codeClass;
    compilerParams.IncludeDebugInformation = false;
    System.Reflection.Assembly myAssembly = System.Reflection.Assembly.GetExecutingAssembly();
    compilerParams.ReferencedAssemblies.Add(myAssembly.Location);
    foreach (System.Reflection.AssemblyName assemblyName in myAssembly.GetReferencedAssemblies())
    {
        if (!excludedAssemblyNames.Contains(assemblyName.Name))
        {
            System.Reflection.Assembly assembly = System.Reflection.Assembly.Load(assemblyName);
            compilerParams.ReferencedAssemblies.Add(assembly.Location);
        }
    }
    return compiler.CompileAssemblyFromSource(compilerParams, code);
}

private static void GetHandle(System.CodeDom.Compiler.CompilerResults compilerResults, string codeNamespace, string codeClass, string codeMethod, out object codeObject, out System.Reflection.MethodInfo codeMethodInfo)
{
    codeObject = compilerResults.CompiledAssembly.CreateInstance(codeNamespace + "." + codeClass);
    if (codeObject == null)
    {
        throw new System.ArgumentException("No class '" + codeClass + "' in namespace '" + codeNamespace + "' found in the C# code", "Error");
    }
    System.Type type = codeObject.GetType();
    codeMethodInfo = type.GetMethod(codeMethod);
    if (codeMethodInfo == null)
    {
        throw new System.ArgumentException("No method '" + codeMethod + "' for class '" + codeClass + "' found in the C# code");
    }
}