Is it possible to compile and execute new code at runtime in .NET?
Asked Answered
L

15

36

Note: Mathematical expression evaluation is not the focus of this question. I want to compile and execute new code at runtime in .NET. That being said...

I would like to allow the user to enter any equation, like the following, into a text box:

x = x / 2 * 0.07914
x = x^2 / 5

And have that equation applied to incoming data points. The incoming data points are represented by x and each data point is processed by the user-specified equation. I did this years ago, but I didn't like the solution because it required parsing the text of the equation for every calculation:

float ApplyEquation (string equation, float dataPoint)
{
    // parse the equation string and figure out how to do the math
    // lots of messy code here...
}

When you're processing boatloads of data points, this introduces quite a bit of overhead. I would like to be able to translate the equation into a function, on the fly, so that it only has to be parsed once. It would look something like this:

FunctionPointer foo = ConvertEquationToCode(equation);
....
x = foo(x);  // I could then apply the equation to my incoming data like this

Function ConvertEquationToCode would parse the equation and return a pointer to a function that applies the appropriate math.

The app would basically be writing new code at run time. Is this possible with .NET?

Lucubrate answered 24/10, 2008 at 16:18 Comment(1)
Possible duplicate of How can I evaluate a C# expression dynamically?Sacksen
L
20

Yes! Using methods found in the Microsoft.CSharp, System.CodeDom.Compiler, and System.Reflection name spaces. Here is a simple console app that compiles a class ("SomeClass") with one method ("Add42") and then allows you to invoke that method. This is a bare-bones example that I formatted down to prevent scroll bars from appearing in the code display. It is just to demonstrate compiling and using new code at run time.

using Microsoft.CSharp;
using System;
using System.CodeDom.Compiler;
using System.Reflection;

namespace RuntimeCompilationTest {
    class Program
    {
        static void Main(string[] args) {
            string sourceCode = @"
                public class SomeClass {
                    public int Add42 (int parameter) {
                        return parameter += 42;
                    }
                }";
            var compParms = new CompilerParameters{
                GenerateExecutable = false, 
                GenerateInMemory = true
            };
            var csProvider = new CSharpCodeProvider();
            CompilerResults compilerResults = 
                csProvider.CompileAssemblyFromSource(compParms, sourceCode);
            object typeInstance = 
                compilerResults.CompiledAssembly.CreateInstance("SomeClass");
            MethodInfo mi = typeInstance.GetType().GetMethod("Add42");
            int methodOutput = 
                (int)mi.Invoke(typeInstance, new object[] { 1 }); 
            Console.WriteLine(methodOutput);
            Console.ReadLine();
        }
    }
}
Lucubrate answered 4/5, 2012 at 23:12 Comment(6)
This is very slow for simple arithmetic expressions though.Deloisedelong
@JonathanNappee: I was just glad to discover how to do this, I didn't say it was great. I would love to see your performance improvements!Lucubrate
@Jonathan Nappee, can you explain your comment some? I want to verify that this method of adding in "Add42" is no slower than having it built-in to the program. To put it another way, your comment was aimed more at "a method that adds 42 is inefficient" rather than "this method of adding code to your program at run time is inefficient," correct?Cubital
@Cubital The very slow part is in the need to compile, create instance and run Invoke. That's probably a few 100s milliseconds overhead. a simple arithmetic parser would be probably an order of magnitude faster.Deloisedelong
@Jonathan Nappee Thanks for explaining. To make sure I understand how best to use (or not use) this: If you can cache the results of the compile and reuse it multiple times it could potentially offset the overhead cost of said compile. Additionally, complex tasks are far more suited to this method as opposed to simple arithmetic, for simple arithmetic you're probably better off with something like Calculator.Net. Are both of these statements true?Cubital
@Cubital Yes both true.Deloisedelong
M
14

You might try this: Calculator.Net

It will evaluate a math expression.

From the posting it will support the following:

MathEvaluator eval = new MathEvaluator();
//basic math
double result = eval.Evaluate("(2 + 1) * (1 + 2)");
//calling a function
result = eval.Evaluate("sqrt(4)");
//evaluate trigonometric 
result = eval.Evaluate("cos(pi * 45 / 180.0)");
//convert inches to feet
result = eval.Evaluate("12 [in->ft]");
//use variable
result = eval.Evaluate("answer * 10");
//add variable
eval.Variables.Add("x", 10);            
result = eval.Evaluate("x * 10");

Download Page And is distributed under the BSD license.

Monteith answered 24/10, 2008 at 16:39 Comment(3)
You'll want to look at the CodeDom namespace then, it is possible to compile code at runtime.Bagdad
This library seems to have some bug and do not seems to still be supported.Cyprian
I tried to use Calculator.NET initially but had to ditch it because exponential calculations didn't seem to work: "11*10^1+13*10^2" resulted in 57600, not 1410.Barnhill
F
8

Yes, definitely possible to have the user type C# into a text box, then compile that code and run it from within your app. We do that at my work to allow for custom business logic.

Here is an article (I haven't more than skimmed it) which should get you started:

http://www.c-sharpcorner.com/UploadFile/ChrisBlake/RunTimeCompiler12052005045037AM/RunTimeCompiler.aspx

Fechter answered 24/10, 2008 at 16:24 Comment(0)
A
7

You can also create a System.Xml.XPath.XPathNavigator from an empty, "dummy" XML stream, and evaluate expressions using the XPath evaluator:

static object Evaluate ( string xp )
{
  return _nav.Evaluate ( xp );
}
static readonly System.Xml.XPath.XPathNavigator _nav
  = new System.Xml.XPath.XPathDocument (
      new StringReader ( "<r/>" ) ).CreateNavigator ( );

If you want to register variables to use within this expression, you can dynamically build XML that you can pass in the Evaluate overload that takes a XPathNodeIterator.

<context>
  <x>2.151</x>
  <y>231.2</y>
</context>

You can then write expressions like "x / 2 * 0.07914" and then x is the value of the node in your XML context. Another good thing is, you will have access to all XPath core functions, which includes mathematics and string manipulation methods, and more stuff.

If you want to take it further, you can even build your own XsltCustomContext(or ill post here on demand) where you can resolve references to extension functions and variables:

object result = Evaluate ( "my:func(234) * $myvar" );

my:func is mapped to a C#/.NET method which takes a double or int as parameter. myvar is registered as a variable within the XSLT context.

Aeneid answered 24/10, 2008 at 18:12 Comment(0)
J
3

You can try looking at either CodeDom or Lambda Expression Trees. I think either one of those should allow you to accomplish this. Expression trees are probably the better way to go but also have a higher learning curve.

Jones answered 24/10, 2008 at 16:21 Comment(0)
D
3

I've done this using CSharpCodeProvider by creating the boiler plate class and function stuff as a const string inside my generator class. Then I insert the user code into the boiler plate and compile.

It was fairly straightforward to do, but the danger to this approach is that the user entering the equation could enter just about anything which could be a security issue depending on your application.

If security is at all a concern, I would recommend using Lambda Expression Trees, but if not, using CSharpCodeProvider is a fairly robust option.

Despoil answered 24/10, 2008 at 16:54 Comment(0)
D
3

Have you seen http://ncalc.codeplex.com ?

It's extensible, fast (e.g. has its own cache) enables you to provide custom functions and varaibles at run time by handling EvaluateFunction/EvaluateParameter events. Example expressions it can parse:

Expression e = new Expression("Round(Pow(Pi, 2) + Pow([Pi2], 2) + X, 2)"); 

  e.Parameters["Pi2"] = new Expression("Pi * Pi"); 
  e.Parameters["X"] = 10; 

  e.EvaluateParameter += delegate(string name, ParameterArgs args) 
    { 
      if (name == "Pi") 
      args.Result = 3.14; 
    }; 

  Debug.Assert(117.07 == e.Evaluate()); 

It also handles unicode & many data type natively. It comes with an antler file if you want to change the grammer. There is also a fork which supports MEF to load new functions.

Despairing answered 10/8, 2011 at 15:7 Comment(0)
C
3

Here a more modern library for simple expressions: System.Linq.Dynamic.Core. It's compatible with .NET Standard/.NET Core, it's available through NuGet, and the source is available.

https://system-linq-dynamic-core.azurewebsites.net/html/de47654c-7ae4-9302-3061-ea6307706cb8.htm https://github.com/StefH/System.Linq.Dynamic.Core https://www.nuget.org/packages/System.Linq.Dynamic.Core/

This is a very lightweight and dynamic library.

I wrote a simple wrapper class for this library that let's me do things like this:

  string sExpression = "(a == 0) ? 5 : 10";
  ExpressionEvaluator<int> exec = new ExpressionEvaluator<int>(sExpression);
  exec.AddParameter("a", 0);
  int n0 = exec.Invoke();

Once the expression is compiled, you can simply update the parameter values and re-invoke the expression.

Coupon answered 20/5, 2018 at 1:41 Comment(0)
B
2

You could start here and if you really want to get into it, Boo can be modified to meet your needs. You could also integrate LUA with .NET. Any three of these could be utilized within the body of a delegate for your ConvertEquationToCode.

Bagdad answered 24/10, 2008 at 16:23 Comment(0)
W
1

Try Vici.Parser: download it here (free) , it's the most flexible expression parser/evaluator I've found so far.

Windgall answered 17/9, 2009 at 12:46 Comment(0)
R
0

If all else fails, there are classes under the System.Reflection.Emit namespace which you can use to produce new assemblies, classes, and methods.

Returnable answered 24/10, 2008 at 19:56 Comment(1)
A word of caution though. We used this on .Less (dotlesscss.com), and emitting code usually means horrible performance.Towny
T
0

You could implement a postfix stack calculator. Basically what you have to do is convert the expression to postfix notation, and then simply iterate over the tokens in your postfix to calculate.

Towny answered 4/2, 2010 at 0:58 Comment(0)
S
-1

I would do a recursive function that doesn't write code but instead applies basic operators to portions of a string based on special characters found in that string. If more than one special character is found, it breaks up the string and calls itself on those two portions.

Sworn answered 24/10, 2008 at 16:23 Comment(1)
What you want is an expression parser. I did this once by converting the expression from infix to postfix then using a stack based posfix parser. Algorithms for both of these are well defined and exist on the web and in books.Mg
O
-1

you can use system.CodeDom to generate code and compile it on the fly have a look here

Offen answered 4/2, 2010 at 0:52 Comment(0)
S
-2

I don't know if it's possible to implement your ConvertEquationToCode function, however, you can generate a data structure that represents the calculation you need to perform.

For example, you could build a tree whose leaf nodes represent the input for your calculation, whose non-leaf nodes represent intermediate results, and whose root node represents the whole calculation.

It has some advantages. For example, if you're doing what-if analysis and want to change the value of one input at a time, you can recalculate the results that depend on the value that you have changed, while retaining the results that don't.

Shaunteshave answered 17/12, 2008 at 19:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.