Как разрешить пользователям определять финансовые формулы в приложении C #

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

Вопрос

Мне нужно позволить своим пользователям возможность определить формулы, которые будут рассчитать значения на основе данных. Например

//Example 1
return GetMonetaryAmountFromDatabase("Amount due") * 1.2;
//Example 2
return GetMonetaryAmountFromDatabase("Amount due") * GetFactorFromDatabase("Discount");

Мне нужно будет разрешить / * + - операции, а также назначать локальные переменные и выполнять, если операторы, как так

var amountDue = GetMonetaryAmountFromDatabase("Amount due");
if (amountDue > 100000) return amountDue * 0.75;
if (amountDue > 50000) return amountDue * 0.9;
return amountDue;

Сценарий сложно, потому что у меня есть следующая структура ..

  1. Клиент (несколько сотен)
  2. Конфигурация (около 10 на заказчик)
  3. Пункт (около 10000 на конфигурацию клиентов)

Поэтому я выполню петлю 3 уровня. На каждом уровне «конфигурация» я начну транзакцию DB и компилируйте TOBLELAS, каждый «элемент» будет использовать ту же транзакцию + скомпилированные формулы (есть около 20 формул на конфигурацию, каждый элемент будет использовать все их).

Это дополнительно усложняет вещи, потому что я не могу просто использовать услуги компилятора, так как оно приведет к продолжению роста использования памяти. Я не могу использовать новый Appdomain на каждой «конфигурации» уровня петли, потому что некоторые ссылки, которые мне нужно пройти, не могут быть маршаллированы.

Какие-либо предложения?

--Update-- это то, с чем я пошел, спасибо!http://www.codeproject.com/articles/53611/embedding-ironpython-in-ac-application

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

Решение

Вы можете создать простой класс во время выполнения, просто записывая логику в строку или тому подобное, компилируйте ее, запустите его и заставляйте его вернуть необходимые вычисления. Эта статья показывает, как получить доступ к компилятору от времени выполнения: http://www.codeproject.com/kb/cs/CodeCompilation.aspx.

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

Железный питон Позволяет встроить сценаривный двигатель в ваше приложение. Есть много других решений. На самом деле, вы можете Google что-то вроде «C # встроенные сценарии» и найти целую кучу вариантов. Некоторые легче, чем другие, чтобы интегрироваться, а некоторые легче, чем другие, чтобы комировать скрипты.

Конечно, всегда есть VBA. Но это просто совершенно некрасиво.

Я столкнулся с подобной проблемой несколько лет назад. У меня было веб-приложение с умеренным трафиком, необходимым для разрешения уравнений, и вам нужны аналогичные функции для вашего, и он должен был быть быстрым. Я прошел несколько идей.

Первое решение приняло участие в добавлении расчетных колонн в нашу базу данных. Наши таблицы для хранения приложений Свойства в столбцах (например, есть столбец для суммы для суммы, другая скидка и т. Д.). Если пользователь, набранный в формуле, такой как HOWENATA * 2, код изменит базовую таблицу, чтобы иметь новый рассчитанный столбец. Это грязно, насколько добавляя и удаление колонн. У него есть несколько преимуществ, хотя: база данных (SQL Server) была действительно быстрой при выполнении расчетов; База данных обрабатывала много обнаружения ошибок для нас; И я мог привести к умолчанию, что рассчитанные значения были такими же, как несчитанные значения, которые означали, что мне не нужно было изменять какой-либо существующий код, который работал с несчитанными значениями.

Это работало некоторое время, пока нам не понадобится способность к формуле ссылаться на другую формулу, а SQL Server не позволяет этого. Поэтому я перешел на сценаривный двигатель. Ironpython не был очень зрелым потом, поэтому я выбрал другой двигатель ... Я не могу вспомнить, какой из них прямо сейчас. Во всяком случае, было легко написать, но это было немного медленно. Не намного, может быть, несколько миллисекунд на запрос, но для веб-приложения в настоящее время действительно добавлено через все запросы.

Это было когда я решил написать свой собственный парсер для формул. То есть у меня есть класс для добавления двух значений, класс ItemToken, который соответствует GetValue («скидками») и т. Д. Когда пользователь входит в новую формулу, валидатор анализирует формулу, гарантирует, что он действителен (подобные вещи, Они ссылаются на столбец, который не существует?), и хранит его в полукомпонентной форме, которая легко разбираться позже. Когда пользователь запрашивает расчетное значение, анализатор читает формулу, разбирает его, определяет, какие данные необходимы из базы данных, и вычисляет окончательный ответ. Это заняло простое количество работы, но работает хорошо, и это действительно быстро. Вот что я узнал:

  1. Если пользователь вводит формулу, которая приводит к циклу в формулах, и вы пытаетесь вычислить значение формулы, у вас будет выходить из пространства стека. Если вы выполняете это в веб-приложении, весь веб-сервер перестанет работать, пока не сбросишь его. Так что важно обнаруживать циклы на этапе проверки.
  2. Если у вас есть больше, чем пара пары, заполнив все вызовы базы данных в одном месте, затем запросите все данные одновременно. Намного быстрее.
  3. Пользователи войдут в Wacky в формулах. Парсер, который предоставляет полезные сообщения об ошибках, сэкономит много головных болей позже.

Если пользовательские скрипты не становятся более сложными, чем те, которые вы показываете выше, я бы согласился с Sylvestre: создайте свой собственный парсер, сделайте дерево и сделайте логику самостоятельно. Вы можете генерировать .Net выражение дерева Или просто пройдите через синтаксическое дерево сами и сделайте операции в собственном коде (antlr ниже поможет вам генерировать такой код).

Тогда вы находитесь в полном контроле над вашими ссылками, вы всегда находитесь в C #, поэтому вам не нужно беспокоиться о управлении памятью (больше, чем обычно вы обычно делаете) и т. Д. IMO Antlr Лучший инструмент для этого в C #. Вы получаете примеры с сайта для небольших языков, как ваш сценарий.

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

Вы можете построить два базовых класса AnararoPerator (если, квадрат, root ...) и BinaryOperator (+ - / *) и построить дерево из выражения. Затем оцените дерево для каждого элемента.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top