Dynamic Formula Evaluation On Runtime

A couple of years ago, I got involved in a project where a developer has ported some code from mainframe to .NET.

The code had to evaluate mathematical formulas on runtime.  This was developed – as the matter of fatct – it was copied from some open source code found on the internet, that could evaluate formulas.  This evaluation was based upon parsing and doing regular expression magic.

There was a couple of problems involved with this approach:

  • Possible licensing issues, by using open source
  • Extremly hard to understand, including long pieces of code blocks (+2.000 lines of code).
  • Poor performance

To solve this, it had to be completly rethinked.  My approach:  as the formulars where static, e.g.   result = param1*param2/param3 this could be expressed using C# code.  So my solution was quite simple:

Each of the formula (actually present in a database), would have its C# code generated on application  start, compiled and internal references to the entry point stored internally.

This way I was able to solve all three problems with the original approach:

  • No problems with licensing
  • The code was cut down to < 100 lines of code (and now even supported more advanced formulas!)
  • The performance was boosted a factor +100!

The secret is of course generating the code on runtime.  This can easily be accomplished by using the CodeDomProvider and in combination with Reflection you will be able both to compile and execute code on runtime.

Here’s a little example:

            using System; 
            using System.CodeDom.Compiler; 
            using System.Reflection; 
            var sourceCode = "using System; namespace Test {  public class MyClass { public int DoCalc() { return 1+2; } } }"; 
            //  Get a reference to the CSharp code provider 
            var codeDomProvider = CodeDomProvider.CreateProvider("csharp"); 
            //  Set compile options (we want to compile in memory) 
            var compileParameters = new CompilerParameters { GenerateInMemory = true }; 
            //  Now compile the supplied source code and compile it. 
            var compileResult = codeDomProvider.CompileAssemblyFromSource(compileParameters, sourceCode); 
            //  If everything goes well (in this example, I know it is correct! :-)) we get a reference to the compiled assembly. 
            var compiledAssembly = compileResult.CompiledAssembly; 
            //  Now, using reflection we can create an instance of our class 
            var inst = compiledAssembly.CreateInstance("Test.MyClass"); 
            //  ... and call a method on it! 
            var callResult = inst.GetType().InvokeMember("DoCalc", BindingFlags.InvokeMethod, null, inst, null);