64

I would like to do the equivalent of:

object result = Eval("1 + 3");
string now    = Eval("System.DateTime.Now().ToString()") as string

Following Biri s link, I got this snippet (modified to remove obsolete method ICodeCompiler.CreateCompiler():

private object Eval(string sExpression)
{
    CSharpCodeProvider c = new CSharpCodeProvider();
    CompilerParameters cp = new CompilerParameters();

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

    cp.CompilerOptions = "/t:library";
    cp.GenerateInMemory = true;

    StringBuilder sb = new StringBuilder("");
    sb.Append("using System;\n");

    sb.Append("namespace CSCodeEvaler{ \n");
    sb.Append("public class CSCodeEvaler{ \n");
    sb.Append("public object EvalCode(){\n");
    sb.Append("return " + sExpression + "; \n");
    sb.Append("} \n");
    sb.Append("} \n");
    sb.Append("}\n");

    CompilerResults cr = c.CompileAssemblyFromSource(cp, sb.ToString());
    if (cr.Errors.Count > 0)
    {
        throw new InvalidExpressionException(
            string.Format("Error ({0}) evaluating: {1}", 
            cr.Errors[0].ErrorText, sExpression));
    }

    System.Reflection.Assembly a = cr.CompiledAssembly;
    object o = a.CreateInstance("CSCodeEvaler.CSCodeEvaler");

    Type t = o.GetType();
    MethodInfo mi = t.GetMethod("EvalCode");

    object s = mi.Invoke(o, null);
    return s;

}  
Daren Thomas
  • 67,947
  • 40
  • 154
  • 200
  • Why is this necessary? I highly doubt that this is the best design for whatever purpose you intend. More than likely there are other mechanisms to produce the results you desire without opening up the huge can of worms (for security and maintainability) that is evaluating code snippets at run time. – Wedge Sep 10 '08 at 22:14
  • I wanted a quick and dirty way to add expression validation to a DSL I wrote. I controll the files being fed to the evaluator, so the can of worms is never opened ;) Also, I only allow one expression, don't add any Namespaces / reference any assemblies. This should stop myself from doing harm too! – Daren Thomas Sep 11 '08 at 06:35
  • 1
    I do this in testing scenarios. I have an assembly that changes version numbers as it gets updated. I'd like my test code to be "late bound" to the assembly - to be able to load the assembly and call into it dynamically. this is a simple matter of reflection. But when I want to implement an interface that is specified in the assembly, it requires dynamic compilation of code, because the interface itself si strongly named (with a version number). I cannot have code that implements IFoo v1.2 when I want to invoke v1.3. Dynamic compilation addresses this. – Cheeso Jun 25 '09 at 02:49
  • 1
    I should say, there are lots of other scenarios as well. It's not the mainstream thing to do, but there are many scenarios where dynamic code compilation makes sense. – Cheeso Jun 25 '09 at 02:49
  • 3
    Remember that unless you do your compilation and execution in a seperate AppDomain, you may run into memory problems. Assemblies generated in this manner cannot be unloaded, but if you create the assembly in a seperate AppDomain you can unload the AppDomain and thereby unload the generated assembly. – JJJ Sep 10 '08 at 12:35

10 Answers10

49

Old topic, but considering this is one of the first threads showing up when googling, here is an updated solution.

You can use Roslyn's new Scripting API to evaluate expressions.

If you are using NuGet, just add a dependency to Microsoft.CodeAnalysis.CSharp.Scripting. To evaluate the examples you provided, it is as simple as:

var result = CSharpScript.EvaluateAsync("1 + 3").Result;

This obviously does not make use of the scripting engine's async capabilities.

You can also specify the evaluated result type as you intended:

var now = CSharpScript.EvaluateAsync<string>("System.DateTime.Now.ToString()").Result;

To evaluate more advanced code snippets, pass parameters, provide references, namespaces and whatnot, check the wiki linked above.

Monso
  • 1,086
  • 8
  • 9
Ridkuma
  • 606
  • 6
  • 5
  • 1
    I love this feature and works really well only complaint was how slow it was – JMIII Aug 03 '18 at 20:25
  • 2
    Terribly slow. adds 30seconds to evaluate simple tertiary 40 expressions – hungryMind May 12 '20 at 13:54
  • 2
    @hungryMind you do not use `EvaluateAsync` at just face value. There are 3 things to consider when using this approach. 1. Roslyn warmup. 2. Expression compilation. 3. Expression evaluation. The first two take 99% of the 40 seconds you see here. If you cache the result of 'CSharpScrip.Create` and use that instead you will get the native performance of the requested string. – Tomasz Juszczak Apr 08 '22 at 20:46
32

I have written an open source project, Dynamic Expresso, that can convert text expression written using a C# syntax into delegates (or expression tree). Text expressions are parsed and transformed into Expression Trees without using compilation or reflection.

You can write something like:

var interpreter = new Interpreter();
var result = interpreter.Eval("8 / 2 + 2");

or

var interpreter = new Interpreter()
                .SetVariable("service", new ServiceExample());

string expression = "x > 4 ? service.aMethod() : service.AnotherMethod()";

Lambda parsedExpression = interpreter.Parse(expression, 
                        new Parameter("x", typeof(int)));

parsedExpression.Invoke(5);

My work is based on Scott Gu article http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx .

Davide Icardi
  • 11,919
  • 8
  • 56
  • 77
  • +1 @Davide lcardi it's very good library, but has some limitations: https://stackoverflow.com/questions/46581067/how-to-make-dynamicexpresso-recognizes-members-using-new-modifier – Dabbas Oct 05 '17 at 08:28
24

If you specifically want to call into code and assemblies in your own project I would advocate using the C# CodeDom CodeProvider.

Here is a list of the most popular approaches that I am aware of for evaluating string expressions dynamically in C#.

Microsoft Solutions

Non-Microsoft solutions (not that there is anything wrong with that)

Coding Seb
  • 83
  • 1
  • 5
cdiggins
  • 17,602
  • 7
  • 105
  • 102
  • Seems you left out a few options (some in other answers here) such as `DataColumn.Expression` and `DataTable.Compute` and the deprecated JScript. – NetMage Oct 09 '20 at 20:50
2
using System;
using Microsoft.JScript;
using Microsoft.JScript.Vsa;
using Convert = Microsoft.JScript.Convert;

namespace System
{
    public class MathEvaluator : INeedEngine
    {
        private VsaEngine vsaEngine;

        public virtual String Evaluate(string expr)
        {
            var engine = (INeedEngine)this;
            var result = Eval.JScriptEvaluate(expr, engine.GetEngine());

            return Convert.ToString(result, true);
        }

        VsaEngine INeedEngine.GetEngine()
        {
            vsaEngine = vsaEngine ?? VsaEngine.CreateEngineWithType(this.GetType().TypeHandle);
            return vsaEngine;
        }

        void INeedEngine.SetEngine(VsaEngine engine)
        {
            vsaEngine = engine;
        }
    }
}
  • There is a better JavaScript implementation called Iron JS. It used the DLR like Iron Python, etc. [Iron Js on NuGet](http://nuget.org/List/Packages/IronJS). As I understand Vsa is obsolete – Jeno Laszlo Jul 22 '11 at 09:34
2

I have just written a similar library (Matheval) in pure C#. It allows evaluating string and number expression like excel fomular.

using System;
using org.matheval;
                    
public class Program
{
    public static void Main()
    {
        Expression expression = new Expression("IF(time>8, (HOUR_SALARY*8) + (HOUR_SALARY*1.25*(time-8)), HOUR_SALARY*time)");
        //bind variable
        expression.Bind("HOUR_SALARY", 10);
        expression.Bind("time", 9);
        //eval
        Decimal salary = expression.Eval<Decimal>();    
        Console.WriteLine(salary);
    }
}
Binh
  • 261
  • 2
  • 4
1

What are the performance implications of doing this?

We use a system based on something like the above mentioned, where each C# script is compiled to an in-memory assembly and executed in a separate AppDomain. There's no caching system yet, so the scripts are recompiled every time they run. I've done some simple testing and a very simple "Hello World" script compiles in about 0.7 seconds on my machine, including loading the script from disk. 0.7 seconds is fine for a scripting system, but might be too slow for responding to user input, in that case a dedicated parser/compiler like Flee might be better.

using System;
public class Test
{
    static public void DoStuff( Scripting.IJob Job)
    {
        Console.WriteLine( "Heps" );
    }
}
JJJ
  • 509
  • 1
  • 6
  • 14
0

Looks like there is also a way of doing it using RegEx and XPathNavigator to evaluate the expression. I did not have the chance to test it yet but I kind of liked it because it did not require to compile code at runtime or use libraries that could not be available.

http://www.webtips.co.in/c/evaluate-function-in-c-net-as-eval-function-in-javascript.aspx

I'll try it and tell later if it worked. I also intend to try it in Silverlight, but it is too late and I'm almost asleep to do it now.

0

While C# doesn't have any support for an Eval method natively, I have a C# eval program that does allow for evaluating C# code. It provides for evaluating C# code at runtime and supports many C# statements. In fact, this code is usable within any .NET project, however, it is limited to using C# syntax. Have a look at my website, http://csharp-eval.com, for additional details.

xnaterm
  • 51
  • 1
0

There is a nice piece of code here https://www.c-sharpcorner.com/article/codedom-calculator-evaluating-c-sharp-math-expressions-dynamica/

Download this and make it a class library which may be referenced in your project. This seems to be pretty fast and simple

Perhaps this could help !

Venugopal M
  • 2,280
  • 1
  • 20
  • 30
0

Just pass your aritmetic expression to sql using a conection string

// INPUT
string eval = "SELECT ((1+2)-3*4)/5.0";

string strCon = $"Server=.\sqlexpress; Database=master; integrated security = true";

SqlConnection sqlCon = new SqlConnection(strCon);
sqlCon.Open();

SqlCommand cmd = new SqlCommand(eval, sqlCon);

SqlDataAdapter da = new SqlDataAdapter(cmd);
string result = da.SelectCommand.ExecuteScalar().ToString();

// OUTPUT
Console.WriteLine(result);

You must add using System.Data.SqlClient;

  • Hmmm... I can see that working but... there's a lot of overhead doing it thar way. Pulling in a whole RDBMS just to evaluate an expression is all kinds of overkill. If there wasn't already a solution, you'd be better off hosting (embedding) a scripting language like javascript, Lua or Python. Or Powershell? – Daren Thomas May 20 '23 at 09:24