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

StackOverflow https://stackoverflow.com/questions/1437964

Вопрос

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

  1. Путем Рекурсивного спуска
  2. Алгоритм маневровой площадки
  3. Обратная польская нотация

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

Это было полезно?

Решение

В дополнение к ответу Томаса, на самом деле можно получить доступ к (устаревшим) библиотекам JScript напрямую из C #, что означает, что вы можете использовать эквивалент функции 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();

Другие советы

Это, конечно, возможно.Тот Самый Codesnippetкомпиляционный модуль класс делает в основном это.Я написал вам несколько примеров кода использования.Вам нужно будет включить эти пространства имен:

  • Система.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 });

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

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

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

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

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

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

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

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

jsc /t:library JsMath.js

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

double result = JsMath.Eval(expression);

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

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

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

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

Я думаю, что это лучший способ из всех. Ответ Петар Репак удивителен. Использование аргумента '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"]);
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top