Create Assembly in-memory and run it…


This has to do with CodeDom and Microsoft.CSharp namespace. The following code will let you compile and run code in memory, IMHO - perfect for scripting engine needs:


using System;
using Specialized = System.Collections.Specialized;
using Reflection = System.Reflection;
using CSharp = Microsoft.CSharp;
using CodeDom = System.CodeDom.Compiler;


public sealed class TestCompile
{


static string ScriptCodeToCompileInMem = "public class Script {public void ScriptExecute(){System.Console.WriteLine(123);} }";
public static void Main()
{
  TestCompile tc = new TestCompile();
  tc.Execute(TestCompile.ScriptCodeToCompileInMem);
}


public void Execute(string scriptCode)
{
  string [] source = new string[1];
  source[0] = scriptCode;
  CSharp.CSharpCodeProvider cscp = new CSharp.CSharpCodeProvider();
  this.Compile(cscp, source[0]);
}



private void Compile(CodeDom.CodeDomProvider provider, string source)
{
  CodeDom.CompilerParameters param = new CodeDom.CompilerParameters();
  param.GenerateExecutable = false;
  param.IncludeDebugInformation = false;
  param.GenerateInMemory = true;
  CodeDom.ICodeCompiler cc = provider.CreateCompiler();
  CodeDom.CompilerResults cr = cc.CompileAssemblyFromSource(param, source);
  Specialized.StringCollection output = cr.Output;
  if(cr.Errors.Count !=0)
  {
    System.Console.WriteLine("Error invoking scripts.");
    CodeDom.CompilerErrorCollection es = cr.Errors;
    foreach(CodeDom.CompilerError s in es)
      System.Console.WriteLine(s.ErrorText);
  }
  else
  {
    object o = cr.CompiledAssembly.CreateInstance("Script");
    System.Type type = o.GetType();
    type.InvokeMember ("ScriptExecute",
            
Reflection.BindingFlags.InvokeMethod |
            Reflection.BindingFlags.Default, null, o, null);
  }
}
}


This posting is provided "AS IS" with no warranties, and confers no rights.

Comments (5)
  1. Scott says:

    I think this abilty can be useful if you think about in the context of creating self-healing applications as well as in a scripting context.

  2. raisch says:

    I wouldn’t recommend C#/.Net as a scripting environment to anyone.

    Sure, the C# compiler is intrinsic to the runtime, and your code allows you to compile and run arbitrary C# code in the context of your application.

    But getting rid of the new assembly once you have created it is not easy. You have to either do your compile in a separate AppDomain or load it into a new AppDomain from disk.

    Once you are finished with it, you have to unload the AppDomain to get rid of the code or your application will grow to consume all available memory. The final problem then is calling your new code across AppDomains.

    The overhead of AppDomain management is daunting, even to just understand, and the time it takes to compile and save an assembly dll is excruciating.

    I’ve been writing systems that create dynamic functionality (perl modules, c++ and delphi dlls, and now C# assemblies) for some time and .Net is the worst platform for plugins and scripting I have ever worked in.

    /rr

  3. Raisch is correct. The things you really need from a scripting language/plugin language don’t really exist under .NET. The AppDomain issue is probably the largest since you can’t unload old versions without loading them in their own/separate AppDomain. Something I consider even more hideous is the inability to truly lock down a .NET assembly. For example, loaded assemblies can do stuff like hang in static constructors forcing you to load them on a separate thread. They can also hang in a finally block which I think hangs the run-time and puts the thread in a state where it can’t be aborted. Even worse they can hang in their finalizer and stop the GC thread. I mean come on, why in the heck are there so many ways to shut down a managed application from *Execute* only code.

  4. Have any of you discovered an effective of way of using dynamically compiled .Net code as a scripting language? Not being able to unload an assembly without using a separate application domain makes it a pain, but I was wondering if anyone’s worked out an efficient way to do it, even if there’s a whole bunch of fiddly crap you have to do to make it work.

  5. juju says:

    /agree. .NET SUCKS for scriptint because you cant unload an individual assembly, you have to use Appdomain crazy method, and it has BRUTAL overhad and not easy to use at all(got TONS of exceptions on serialization/marshal etc). In my case, i wanted to use c# to copy some functionality of the Unreal engine, where you can modify the script of and object(actor) and then the level designer recompiles the scripts.

Comments are closed.

Skip to main content