在运行时评估表达式

时间:2011-01-04 19:55:11

标签: c# .net parsing evaluation

我有一个C#控制台应用程序项目。

我有一个逻辑表达式,作为nvarchar存储在数据库中。

例如,存储的表达式是:((34> 0)||(US == ES))&& (4312 = 5691)

当我的应用程序运行时,我想检索表达式并对其进行评估,以便结果为true或false。

我怎样才能在运行时这样做?

3 个答案:

答案 0 :(得分:7)

这是一个非常不寻常的解决方案,涉及JScript:

  • 使用以下代码创建JScript类:

    public class JsMath {
        public static function Eval(expression:String) : Object {
            return eval(expression);
        }
    }
    
  • 将其编译为DLL:

    jsc /target:library /out:JsMath.dll JsMath.js
    
  • 在您的C#项目中,引用JsMath.dll和Microsoft.JScript.dll

  • 现在您可以使用Eval方法,如下所示:

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

优点:

  • 解析表达式无需任何工作,JScript引擎为您完成
  • 无需编译任意代码(如果用户输入代码,则可能是一个很大的安全漏洞)
  • 应该使用任何简单的数学或逻辑表达式,只要它遵循JScript语法

缺点:

  • 无法传递变量(据我所知)
  • 需要引用JScript程序集(在大多数情况下不是一个大问题,但我不确定此程序集在Client Profile或Silverlight中是否可用)

答案 1 :(得分:3)

您可以将表达式解析为.NET Expression类,然后编译并运行它以获得结果。

该类已经支持您示例中的所有逻辑操作,但它似乎含糊不清(您以非常类似的方式使用===)。

您必须编写自己的解析器/转换器。

答案 2 :(得分:0)

我从此处(https://odetocode.com/articles/80.aspx)编写了K. Scott Allen的JScript内联Eval调用程序的更紧凑和有效的版本:

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);
    }
}

只需像这样使用它:

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

返回:

5.05050505050505

如果需要,您也可以扩展它以传递变量值。传入名称和值的字典。静态类的首次使用将花费100-200ms,之后它几乎是瞬时的,不需要单独的DLL。如果需要,可以调用JS.Prepare()进行预编译以停止初始延迟。