5

I'm looking into solutions to convert a string into executeable code. My code is extremely slow and executes at 4.7 seconds. Is there any faster way of doing this?

String: "5 * 5"

Output: 25

The code:

class Program {

    static void Main(string[] args) {
        var value = "5 * 5";
        Stopwatch sw = new Stopwatch();
        sw.Start();
        var test = Execute(value);
        sw.Stop();
        Debug.WriteLine($"Execute string at: {sw.Elapsed}");
    }

    private static object Execute(string content) {
        var codeProvider = new CSharpCodeProvider();
        var compilerParameters = new CompilerParameters {
            GenerateExecutable = false,
            GenerateInMemory = true
        };

        compilerParameters.ReferencedAssemblies.Add("system.dll");

        string sourceCode = CreateExecuteMethodTemplate(content);
        CompilerResults compilerResults = codeProvider.CompileAssemblyFromSource(compilerParameters, sourceCode);
        Assembly assembly = compilerResults.CompiledAssembly;
        Type type = assembly.GetType("Lab.Cal");
        MethodInfo methodInfo = type.GetMethod("Execute");

        return methodInfo.Invoke(null, null);
    }

    private static string CreateExecuteMethodTemplate(string content) {
        var builder = new StringBuilder();

        builder.Append("using System;");
        builder.Append("\r\nnamespace Lab");
        builder.Append("\r\n{");
        builder.Append("\r\npublic sealed class Cal");
        builder.Append("\r\n{");
        builder.Append("\r\npublic static object Execute()");
        builder.Append("\r\n{");
        builder.AppendFormat("\r\nreturn {0};", content);
        builder.Append("\r\n}");
        builder.Append("\r\n}");
        builder.Append("\r\n}");

        return builder.ToString();
    }
}
Community
  • 1
  • 1
MrProgram
  • 4,386
  • 13
  • 52
  • 88
  • 1
    Note that you are not *only* executing code. You are building a string, then compiling it to MSIL, then it gets JITted, and *then* actually executed. If you want to measure the actual performance, create the compiled method outside the benchmark. You might even want to call `RuntimeHelpers.PrepareDelegate` to JIT it before starting the benchmark. And then, call it million times in succession to get the average time. – Groo May 06 '16 at 10:56
  • Did you have a look at this thread? http://stackoverflow.com/questions/234217/is-it-possible-to-compile-and-execute-new-code-at-runtime-in-net Not saying this is duplicate, but I think it can give you some good alternative approaches to try and benchmark. – zoubida13 May 06 '16 at 10:57
  • 1
    Compiling makes sense only when your code executes more than once, i.e. because you call it multiple times, or because it has a loop. When you call a piece of code once, and your code has no loops, interpreting will be faster than compiling. – Sergey Kalinichenko May 06 '16 at 10:59
  • Not clear: you want to perform only mathematical or arbitrary calculations? – Slava Utesinov May 06 '16 at 11:02
  • @SlavaUtesinov mathematical – MrProgram May 06 '16 at 11:07

1 Answers1

7

Well, there is an easier hack:

var _Result = new DataTable().Compute("5*5"); // _Result = 25
var _Result2 = new DataTable().Compute("5+5*5"); // _Result2 = 30

It also has more options. Please have a look at the Documentation.

Kamil T
  • 2,204
  • 1
  • 15
  • 25
  • +1 While it's possible that OP needs more than math operations, this is actually a pretty cool hack. :-D – Groo May 06 '16 at 11:07
  • This was actually pretty cool and even though it's a "hack" it fills my purpose :) thanks – MrProgram May 06 '16 at 11:16