简体   繁体   中英

Evaluating Expression at Runtime

I have a C# Console Application project.

I have a logical expression that is stored in database as nvarchar.

For example, the stored expression is: ((34 > 0) || (US == ES)) && (4312 = 5691)

While my application running, I want to retrieve the expression and evaluate it so that the result will be true or false.

How can I do it at runtime?

Here's a rather unusual solution, involving JScript:

  • Create a JScript class with the following code:

     public class JsMath { public static function Eval(expression:String) : Object { return eval(expression); } } 
  • Compile it into a DLL:

     jsc /target:library /out:JsMath.dll JsMath.js 
  • In your C# project, reference JsMath.dll and Microsoft.JScript.dll

  • Now you can use the Eval method as follows:

     string expression = "((34 > 0) || ('US' == 'ES')) && (4312 == 5691)"; bool result = (bool)JsMath.Eval(expression); 

Benefits:

  • no work required to parse the expression, the JScript engine does it for you
  • no need to compile arbitrary code (which can be a big security hole if the code is entered by the user)
  • should work with any simple mathematical or logical expression, as long as it follows the JScript syntax

Drawbacks:

  • no way to pass variables (as far as I know)
  • requires a reference to the JScript assembly (not a big issue in most cases, but I'm not sure this assembly is available in the Client Profile or in Silverlight)

You can parse the expression into the .NET Expression class and compile and run it in order to get the result.

The class already supports all the logical operations you have in your example, though it appears to be ambiguous (you are using both == and = in a very similar manner).

You will have to write your own parser/converter though.

I have written a more compact and efficient version of K. Scott Allen's JScript inline Eval caller from here ( https://odetocode.com/articles/80.aspx ):

using System;
using System.CodeDom.Compiler;
using Microsoft.JScript;

class JS
{
    private delegate object EvalDelegate(String expr);
    private static EvalDelegate moEvalDelegate = null;

    public static object Eval(string expr)
    {
        return moEvalDelegate(expr);
    }

    public static T Eval<T>(string expr)
    {
        return (T)Eval(expr);
    }

    public static void Prepare()
    {
    }

    static JS()
    {
        const string csJScriptSource = @"package _{ class _{ static function __(e) : Object { return eval(e); }}}";
        var loParameters = new CompilerParameters() { GenerateInMemory = true };
        var loMethod = (new JScriptCodeProvider()).CompileAssemblyFromSource(loParameters, csJScriptSource).CompiledAssembly.GetType("_._").GetMethod("__");
        moEvalDelegate = (EvalDelegate)Delegate.CreateDelegate(typeof(EvalDelegate), loMethod);
    }
}

Just use it like this:

JS.Eval<Double>("1 + 4 + 5 / 99");

Returns:

5.05050505050505

You could extend it to pass in variable values as well if you wanted to, eg pass in a dictionary of names & values. First usage of the static class will take 100-200ms, after that its pretty much instantaneous and doesn't require a separate DLL. Call JS.Prepare() to pre compile to stop the initial delay if you want.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM