最好和最短的方式来评估mathexpression式
有很多algorithm来评估expression式,例如:
- 通过recursion下降
- 调车码algorithm
- 逆波兰记法
有什么办法来评估任何使用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"]); }