Подтвердить что ты не робот

Лучший и самый короткий способ оценки математических выражений

Существует множество алгоритмов для оценки выражений, например:

Есть ли способ оценить любое математическое выражение, используя С#.net-отражение или другую современную технологию .net?

4b9b3361

Ответ 1

Кроме ответа Томаса, на самом деле можно получить доступ к (устаревшим) библиотекам 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();

Ответ 2

Это, безусловно, возможно. Класс 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 });

Заменить "параметры" и "выражение" на что угодно, и у вас есть общий оценщик выражений.

Если вы получите FileNotFoundException в results.CompiledAssembly, тогда фрагмент не удалось скомпилировать.

Вы также можете взглянуть на класс System.CodeDom.CodeSnippetExpression. Он используется для более точного чтения выражений, но само выражение не может быть скомпилировано, поэтому вам нужно будет использовать больше CodeDom для создания рабочего класса и метода вокруг него. Это полезно, если вы хотите иметь возможность программно манипулировать тем, какой класс вы генерируете. CodeSnippetCompileUnit приятно создавать целый рабочий класс сразу (и проще для примера), но для его манипулирования вам придется делать неудобные строковые манипуляции.

Ответ 3

Хотя использование служб компилятора - простое и эффективное решение, оно вызывает серьезные проблемы безопасности, если выражение введено пользователем, потому что оно может выполнять практически все.

Есть еще одно очень простое решение, которое намного безопаснее: воспользуйтесь функцией JScript Eval. Вам просто нужно выполнить следующие действия:

Создайте файл js с именем JsMath.js:

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

Скомпилируйте его в библиотеку классов:

jsc /t:library JsMath.js

Ссылка на библиотеку JsMath в вашем проекте С# и его использование следующим образом:

double result = JsMath.Eval(expression);

Ответ 4

Для меня Vici.Parser работает очень хорошо: проверьте здесь, это самый гибкий парсер выражений, который я нашел до сих пор.

(мы использовали его для создания "удобочитаемых" бизнес-правил с данными, предоставляемыми базой данных SQL-сервера)

Имеются примеры и очень хорошая поддержка разработчика (проверьте форум на сайте).

Ответ 5

ncalc является лучшим. вы можете найти его в codeplex также в самородок.
NCalc является оценщиком математических выражений в .NET. NCalc может анализировать любое выражение и оценивать результат, включая статические или динамические параметры и пользовательские функции.

Ответ 6

Я думаю, что это лучший способ для всех. Ответ Petar Repac поразителен. Использование аргумента 'expression' объекта DataColumn решает невероятно и легко:

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