views:

125

answers:

6

I was wondering if it was possible to compile, and run stored code, without generating an exe or any type of other files, basically run the file from memory.

Basically, the Main application, will have some stored code (code that will potentially be changed), and it will need to compile the code, and execute it. without creating any files.

creating the files, running the program, and then deleting the files is not an option. the compiled code will need to be ran from memory.

code examples, or pointers, or pretty much anything is welcome :)

+1  A: 

Yes, you can do this. It is very slow, but you can certainly do it. Look at the CodeDOM or the (new CSharpCodeProvider().CreateCompiler()) in .Net.

Brian Genisio
+1  A: 

Look into System.CodeDom. It will do exactly what you are looking for.

Seattle Leonard
`System.CodeDom` is the most pleasant option, but it still invokes the compiler and generates an assembly in the temp folder
Tim Robinson
+3  A: 

It's possible. It's easy or hard, depending on how much and what kind of code you want to write.

Edit: Note that, prior to .NET 4.0, System.Linq.Expressions is limited to what you can fit on a single line of C#: that is, no if, while, variable assignment etc.

Tim Robinson
Don't be so quick to say `System.Linq.Expressions` is limited. Although it doesn't have the power of `System.Reflection.Emit` I have compiled massive programs with it. The ability to view the expression tree in a debug view is extremely helpful.
ChaosPandion
I like `System.Linq.Expressions` a lot :). It's just that, prior to .NET 4.0, it's limited to what you can fit on a single line of C# (i.e. no `if`, `while`, variable assignment etc.)
Tim Robinson
@Tim - Oh that makes more sense. I have only used it in .NET 4.0.
ChaosPandion
There is a third alternative - `Microsoft.CSharp`.
Daniel Brückner
@Tim: would you mind providing a simple code example? because ive been playing with options but they mostly seem to generate an assembly and I'm not sure how this is any different... (im mostly interested in compiling whole programs, so, system.reflection.emit?)
Tommy
F# not C#, but it demonstrates the principle: http://www.partario.com/blog/2009/06/lisp-compiler-in-f-il-generation.html
Tim Robinson
@Tim - Rather nicely I might add. It is awesome to see that F# is being used more and more.
ChaosPandion
+4  A: 
using (Microsoft.CSharp.CSharpCodeProvider foo = 
           new Microsoft.CSharp.CSharpCodeProvider())
{
    var res = foo.CompileAssemblyFromSource(
        new System.CodeDom.Compiler.CompilerParameters() 
        {  
            GenerateInMemory = true 
        }, 
        "public class FooClass { public string Execute() { return \"output!\";}}"
    );

    var type = res.CompiledAssembly.GetType("FooClass");

    var obj = Activator.CreateInstance(type);

    var output = type.GetMethod("Execute").Invoke(obj, new object[] { });
}

This compiles a simple class from the source code string included, then instantiates the class and reflectively invokes a function on it.

Adam Robinson
`GenerateInMemory = true` doesn't do what its name suggests; it generates an assembly in the temp directory that you have to delete once you're done.
Tim Robinson
@Tim: I'll admit to not being intimately acquainted with the CodeDom, but I haven't been able to find any evidence to back this up (on my hard drive in the `temp` directory or the application directory, nor on the web in a quick search). Could you point me to a resource that can confirm this?
Adam Robinson
OK - last time I did this I must have kept the assemblies on disk for debugging. I can see that `CSharpCodeProvider` compiles to a temporary file, loads that file using `Assembly.Load(byte[])`, then deletes it. (It can't bypass the temp file completely because it runs _csc.exe_ underneath.)
Tim Robinson
@Tim: Ah, perfect, that's exactly what I was looking for. Thanks for looking into that!
Adam Robinson
@Adam, Tim: I ideally would want a system that would not create an assembly at all. Is there anyway to get CSharpCodeProvider to not create the assembly?
Tommy
No, it's a fundamental limitation in the csc.exe compiler. Ironically, the compiler is written in native C++, and can't interact with your program.
Tim Robinson
@Adam: As a side note, how would I pass arguments while invoking methods?
Tommy
A: 

Also take a look at embedding a scripting language like Python, Ruby, Lua, etc.. all of those support executing code from memory without anything being written to the disk.

Jason Miesionczek
+3  A: 

Here is an example of how to use System.Linq.Expressions to add to Tim's answer. Obviously it isn't the prettiest code but having it in this nice tree-like form makes development so easy.

private  Expression<IsWordChar> CreateIsWordCharExpression()
{
    var e = Expression.Parameter(typeof(int), "e");
    var c = Expression.Variable(typeof(char), "c");
    var returnLabel = Expression.Label(Expression.Label(typeof(bool)), _falseConstant);
    var lambda = Expression.Lambda<IsWordChar>(
        Expression.Block(
            new[] { c },
            Expression.IfThen(
                Expression.OrElse(
                    Expression.Equal(e, Expression.Constant(-1)),
                    Expression.Equal(e, _inputLengthVar)
                ),
                Expression.Return(returnLabel.Target, _falseConstant)
            ),
            Expression.Assign(c, Expression.MakeIndex(_str, _stringCharsPropertyInfo, new[] { e })),
            Expression.IfThenElse(
                Expression.OrElse(
                    Expression.OrElse(
                        Expression.OrElse(
                            Expression.AndAlso(
                                Expression.GreaterThanOrEqual(c, Expression.Constant('a')),
                                Expression.LessThanOrEqual(c, Expression.Constant('z'))
                            ),
                            Expression.AndAlso(
                                Expression.GreaterThanOrEqual(c, Expression.Constant('A')),
                                Expression.LessThanOrEqual(c, Expression.Constant('Z'))
                            )
                        ),
                        Expression.AndAlso(
                            Expression.GreaterThanOrEqual(c, Expression.Constant('0')),
                            Expression.LessThanOrEqual(c, Expression.Constant('1'))
                        )
                    ),
                    Expression.Equal(c, Expression.Constant('_'))
                ),
                Expression.Return(returnLabel.Target, _trueConstant),
                Expression.Return(returnLabel.Target, _falseConstant)
            ),
            returnLabel
        ),
        "IsWordChar",
        new[] { e }
    );
    return lambda;
}
ChaosPandion