2

Short question, Is there a way in .NET 4.0 to take a string that represents the method body, and compile it into a Func/Action, or is there a library to do so?

Clarification:

I need something that will not generate any dll, it needs to be completely dynamic, something like eval() in javascript. I need to convert string into a Func/Action without creating dll.

epitka
  • 17,275
  • 20
  • 88
  • 141
  • you mean something that JavaScript does with eval() ? – Anil Namde Feb 03 '11 at 13:39
  • 2
    Are you looking for a runtime or design time solution? If the latter, you could always use code generation templates like MyGeneration or T4? If the former, have you looked at the Microsoft.CSharp and System.CodeCom.Compiler namespaces? – bitxwise Feb 03 '11 at 13:39

3 Answers3

4

You can use the CSharpCodeProvider class to compile source code into an assembly.

For example:

var compiler = new CSharpCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v4.0" } });
var options = new CompilerParameters { OutputAssembly = path);
var results = compiler.CompileAssemblyFromFile(options, sourceFile);

To compile a single function, you can wrap it in a class with appropriate using statements to create a complete source file, then get a delegate using Reflection:

var assembly = results.CompiledAssembly;
var method = assembly.GetType("WrapperClassName").GetMethod("MethodName");
var delegate = (Action)Delegate.CreateDelegate(typeof(Action), method);

For a more complete example:

static readonly Assembly[] References = new[] { typeof(Enumerable).Assembly, typeof(Component).Assembly };
public Action CompileMethodstring source) {
    var options = new CompilerParameters(References.Select(a => a.Location).ToArray()) {
        GenerateInMemory = true
    };
    string fullSource = @"public static class HolderClass { public static void Execute() { \r\n" + source + "\r\n} }";
    try {
        var compiler = new CSharpCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v4.0" } });

        var results = compiler.CompileAssemblyFromSource(options, fullSource);

        if (results.Errors.Count > 0)
            throw new InvalidOperationException(String.Join(
                Environment.NewLine, 
                results.Errors.Cast<CompilerError>().Select(ce => ce.ErrorText)
            ));

        return (Action)Delegate.CreateDelegate(
            typeof(Action),
            results.CompiledAssembly.GetType("HolderClass").GetMethod("Execute")
        );
    } finally { options.TempFiles.Delete(); }
}
Community
  • 1
  • 1
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
1

You could also use CS-Script.Net It is an embedded scripting platform that also you to do the following:

dynamic script = CSScript.LoadCode(@"using System;
                                     public class Script
                                     {
                                         public void SayHello(string greeting)
                                         {
                                             Console.WriteLine(greeting);
                                         }
                                     }")
                                    .CreateObject("*");
script.SayHello("Hello World!");

I've been using in production for almost 2 years now and it has been a great way to create configurable applications. I have a sample project if you are interested.

David Robbins
  • 9,996
  • 7
  • 51
  • 82
  • This looks very promising. Do you know if it works in medium trust? – epitka Feb 13 '11 at 14:39
  • As far as I know, yes. Here is a link to the scripting models that it supports: http://csscript.net/help/Type_sharing_patern.html. Oleg the project owner is very responsive and you can always contact him with additional questions. – David Robbins Feb 14 '11 at 14:20
0

The CSharpCodeProvider might be what you are looking for. However, you'll need to create valid C# code (meaning, you'll need to create a class for that method).

Femaref
  • 60,705
  • 7
  • 138
  • 176