tags:

views:

1698

answers:

5

I was wondering if it is possible to save C# code fragments to a text file (or any input stream), and then execute those dynamically? Assuming what is provided to me would compile fine within any Main() block, is it possible to compile and/or execute this code? I would prefer to compile it for performance reasons.

At the very least, I could define an interface that they would be required to implement, then they would provide a code 'section' that implemented that interface.

+1  A: 

To compile you could just initiate a shell call to the csc compiler. You may have a headache trying to keep your paths and switches straight but it certainly can be done.

C# Corner Shell Examples

EDIT: Or better yet, use the CodeDOM as Noldorin suggested...

Gary.Ray
Yeah, the nice thing with CodeDOM is that it can generate the assembly for you in memory (as well as providing error messages and other info in an easily readable format).
Noldorin
@Noldorin, The C# CodeDOM implementation doesn't actually generate an assembly in memory. You can enable the flag for it, but it gets ignored. It uses a temporary file instead.
Matt Olenik
@Matt: Yeah, good point - I forgot that fact. Nonetheless, it still greatly simplifies the process (makes it effectively *appear* as if the assembly were generated in memory), and offers a complete managed interface, which is much nicer than dealing with processes.
Noldorin
+9  A: 

The best solution in C#/all static .NET languages is to use the CodeDOM for such things. (As a note, its other main purpose is for dynamically constructing bits of code, or even whole classes.)

Here's a nice short example take from LukeH's blog, which uses some LINQ too just for fun.

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CSharp;
using System.CodeDom.Compiler;

class Program
{
    static void Main(string[] args)
    {
        var csc = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } });
        var parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.Core.dll" }, "foo.exe", true);
        parameters.GenerateExecutable = true;
        CompilerResults results = csc.CompileAssemblyFromSource(parameters,
        @"using System.Linq;
            class Program {
              public static void Main(string[] args) {
                var q = from i in Enumerable.Rnge(1,100)
                          where i % 2 == 0
                          select i;
              }
            }");
        results.Errors.Cast<CompilerError>().ToList().ForEach(error => Console.WriteLine(error.ErrorText));
    }
}

The class of primary importance here is the CSharpCodeProvider which utilises the compiler to compile code on the fly. If you want to then run the code, you just need to use a bit of reflection to dynamically load the assembly and execute it.

Here is another example in C# that (although slightly less concise) additionally shows you precisely how to run the runtime-compiled code using the System.Reflection namespace.

Noldorin
+1 for CodeDOM - I completely forgot about that.
Gary.Ray
Although I doubt your using Mono, I thought it might be worthwhile pointing out that there exists a Mono.CSharp namespace (http://www.mono-project.com/CSharp_Compiler) which actually contains a compiler as a service so that you can dynamically run basic code/evaluate expressions inline, with minimal hassle.
Noldorin
what would be a real world need for doing this. I'm pretty green at programing in general and i think this is cool but i can't think of a reason why you would want / this would be useful. Thanks if you can explain.
Crash893
@Crash893: A scripting system for pretty much any sort of designer application could make good use of this. Of course, there are alternatives such as IronPython LUA, but this is certainly one. Note that a plugin system would be better developed by exposing interfaces and loading compiled DLLs that contain implementations of them, rather than loading code directly.
Noldorin
I always thought of "CodeDom" as the thing which let me create a code file using a DOM - a document object model. In System.CodeDom, there are objects to represent all the artifacts that code includes - an object for a class, for an interface, for a constructor, a statement, a property, a field, and so on. I can then construct code using that object model. What is shown here in this answer is compiling a code file, in a program. Not CodeDom, though like CodeDom, it dynamically produces an assembly. The analogy: I can create an HTML page using the DOM, or using string concats.
Cheeso
here's a SO article that shows CodeDom in action: http://stackoverflow.com/questions/865052/programatically-generating-assemblies-from-owl-files-with-rowlex
Cheeso
@Cheeso: CodeDom has *both* of these purposes: to compile source code into assemblies as well as to generate code dynamically.
Noldorin
A: 

The System.CodeDom.Compiler namespace should help. See this article

FryGuy
A: 

Sounds like what you want is a plugin architecture. See this article.

C. Ross
+3  A: 

Others have already given good answers on how to generate code at runtime so I thought I would address your second paragraph. I have some experience with this and just want to share a lesson I learned from that experience.

At the very least, I could define an interface that they would be required to implement, then they would provide a code 'section' that implemented that interface.

You may have a problem if you use an interface as a base type. If you add a single new method to the interface in the future all existing client-supplied classes that implement the interface now become abstract, meaning you won't be able to compile or instantiate the client-supplied class at runtime.

I had this issue when it came time to add a new method after about 1 year of shipping the old interface and after distributing a large amount of "legacy" data that needed to be supported. I ended up making a new interface that inherited from the old one but this approach made it harder to load and instantiate the client-supplied classes because I had to check which interface was available.

One solution I thought of at the time was to instead use an actual class as a base type such as the one below. The class itself can be marked abstract but all methods should be empty virtual methods (not abstract methods). Clients can then override the methods they want and I can add new methods to the base class without invalidating existing client-supplied code.

public abstract class BaseClass
{
    public virtual void Foo1() { }
    public virtual bool Foo2() { return false; }
    ...
}

Regardless of whether this problem applies you should consider how to version the interface between your code base and the client-supplied code.

Brian Ensink
that is a valuable, helpful perspective.
Cheeso