最好和最短的方式来评估mathexpression式

有很多algorithm来评估expression式,例如:

  1. 通过recursion下降
  2. 调车码algorithm
  3. 逆波兰记法

有什么办法来评估任何使用C#.netreflection或其他现代.NET技术的mathexpression式?

除了Thomas的回答之外,实际上可以直接从C#访问(不build议使用的)JScript库,这意味着您可以使用JScript的eval函数的等价物。

 using Microsoft.JScript; // needs a reference to Microsoft.JScript.dll using Microsoft.JScript.Vsa; // needs a reference to Microsoft.Vsa.dll // ... string expr = "7 + (5 * 4)"; Console.WriteLine(JScriptEval(expr)); // displays 27 // ... public static double JScriptEval(string expr) { // error checking etc removed for brevity return double.Parse(Eval.JScriptEvaluate(expr, _engine).ToString()); } private static readonly VsaEngine _engine = VsaEngine.CreateEngine(); 

这当然是可能的。 CodeSnippetCompileUnit类基本上这样做。 我写了一些示例使用代码。 你需要包含这些命名空间:

  • System.CodeDom.Compiler;
  • System.CodeDom;
  • Microsoft.CSharp;
  • 的System.Reflection;

代码如下:

 string source = @" class MyType { public static int Evaluate(<!parameters!>) { return <!expression!>; } } "; string parameters = "int a, int b, int c"; string expression = "a + b * c"; string finalSource = source.Replace("<!parameters!>", parameters).Replace("<!expression!>", expression); CodeSnippetCompileUnit compileUnit = new CodeSnippetCompileUnit(finalSource); CodeDomProvider provider = new CSharpCodeProvider(); CompilerParameters parameters = new CompilerParameters(); CompilerResults results = provider.CompileAssemblyFromDom(parameters, compileUnit); Type type = results.CompiledAssembly.GetType("MyType"); MethodInfo method = type.GetMethod("Evaluate"); // The first parameter is the instance to invoke the method on. Because our Evaluate method is static, we pass null. int result = (int)method.Invoke(null, new object[] { 4, -3, 2 }); 

用任何东西replace“参数”和“expression式”,你就有了一个通用的expression式求值器。

如果在results.CompiledAssembly中发生FileNotFoundException,则代码片段无法编译。

你可能也想看看System.CodeDom.CodeSnippetExpression类。 它用于更具体的阅读expression式,但是expression式本身不能被编译,所以你需要使用更多的CodeDom来构build一个工作类和方法。 如果你想以编程方式操作你正在生成的类,这是非常有用的。 CodeSnippetCompileUnit很好地同时生成一个完整的工作类(对于一个简单的例子),但是操纵它你必须做不方便的string操作。

尽pipe使用编译器服务是一个简单而有效的解决scheme,但是如果expression式是由用户input的,则会引起严重的安全问题,因为它几乎可以执行任何操作

还有另一个非常简单的解决scheme更安全:利用JScript Eval函数。 您只需要按照以下步骤操作:

创build一个名为JsMath.js的js文件:

 class JsMath { static function Eval(expression : String) : double { return eval(expression); }; } 

编译成类库:

 jsc /t:library JsMath.js 

引用C#项目中的JsMath库,并像这样使用它:

 double result = JsMath.Eval(expression); 

对我来说Vici.Parser工作得非常好: 在这里检查一下 ,这是迄今为止我find的最灵活的expression式parsing器。

(我们用它来build立'人类可读的'业务规则,数据由SQL服务器数据库提供)

例子是可用的,有一个非常好的开发者支持(检查网站的论坛)。

ncalc是最好的。 你也可以在codeplex中find它的块。
NCalc是.NET中的一个mathexpression式求值器。 NCalc可以parsing任何expression式并评估结果,包括静态或dynamic参数和自定义函数。

我认为这是最好的方式。 Petar Repac的答案是惊人的。 使用DataColumn对象的“expression式”参数很容易地解决这个话题:

 static double Evaluate(string expression) { var loDataTable = new DataTable(); var loDataColumn = new DataColumn("Eval", typeof(double), expression); loDataTable.Columns.Add(loDataColumn); loDataTable.Rows.Add(0); return (double)(loDataTable.Rows[0]["Eval"]); }