有很多计算表达式的算法,例如:

  1. 通过递归下降
  2. 调车场算法
  3. 逆波兰表示法

有没有办法使用 C# .net 反射或其他现代 .net 技术来计算任何数学表达式?

有帮助吗?

解决方案

除了Thomas的答案之外,实际上可以直接从C#访问(已弃用的)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();

其他提示

这当然是可能的。这 代码片段编译单元 类基本上就是这样做的。我给你写了一些示例使用代码。您需要包含这些命名空间:

  • 系统.CodeDom.编译器;
  • 系统.CodeDom;
  • 微软.CSharp;
  • 系统.反射;

这是代码:

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

将“参数”和“表达式”替换为任何内容,您就拥有了一个通用表达式求值器。

如果您在 results.CompiledAssembly 中收到 FileNotFoundException,则该代码段无法编译。

您可能还想查看 System.CodeDom.CodeSnippetExpression 类。它用于更具体地读取表达式,但表达式本身无法编译,因此您需要使用更多 CodeDom 来围绕它构建工作类和方法。如果您希望能够以编程方式操作正在生成的类的类型,这非常有用。CodeSnippetCompileUnit 很适合一次生成整个工作类(对于示例来说更简单),但要操作它,您将不得不进行不方便的字符串操作。

尽管使用编译器服务是一种简单而有效的解决方案,但如果用户输入表达式,则会引发严重的安全问题,因为它可以执行虚拟任何

另一个非常简单的解决方案更加安全:利用JScript Eval 功能。您只需按照以下步骤操作:

创建一个名为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工作得非常好:在这里查看,这是到目前为止我发现的最灵活的表达式解析器。

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

示例可用,开发人员提供了非常好的支持(查看网站论坛)。

ncalc 是最好的。您也可以在 codeplex 中找到它。 NCalc是.NET中的数学表达式求值器。 NCalc可以解析任何表达式并评估结果,包括静态或动态参数和自定义函数。

我认为这是最好的方式。 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"]);
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top