Expression: формулы, входы и ошибки
Разделяйте Parse и Execute, проверяйте тип результата и не читайте устаревшую ошибку.
Порядок работы
- Parse разбирает строку и имена входов. Продолжайте только при Error.Ok.
- Execute получает значения в том же порядке, что inputNames. Это синтаксис Expression, не выполнение C#.
- После Execute проверьте HasExecuteFailed, затем тип результата. Nil может быть корректным результатом выражения null.
GetErrorText читайте после обнаруженной ошибки. Успешный Execute может оставить текст предыдущего сбоя, поэтому непустой текст сам по себе не означает текущую ошибку. Новый Parse очищает текст и заменяет разобранное выражение.
Полный числовой адаптер
NumericExpression.cs
using System;
using Reckfell;
public sealed class NumericExpression : IDisposable
{
private readonly Expression _expression = new();
private bool _parsed;
private int _inputCount;
public bool TryParse(string formula, string[] names, out string error)
{
_parsed = false;
error = "";
if (_expression.Parse(formula, names) != Error.Ok)
{
error = _expression.GetErrorText();
return false;
}
_inputCount = names.Length;
_parsed = true;
return true;
}
public bool TryEvaluate(double[] values, out double number, out string error)
{
number = 0;
error = "";
if (!_parsed || values.Length != _inputCount)
{
error = "Parse first and supply one value per input name.";
return false;
}
using var inputs = new Reckfell.Collections.Array();
foreach (double value in values)
{
if (!double.IsFinite(value))
{
error = "Inputs must be finite numbers.";
return false;
}
inputs.Add(value);
}
using Variant result = _expression.Execute(inputs, null, false, true);
if (_expression.HasExecuteFailed())
{
error = _expression.GetErrorText();
return false;
}
if (result.VariantType is not (Variant.Type.Int or Variant.Type.Float) ||
!double.IsFinite(result.AsDouble()))
{
error = "Expected a finite numeric result.";
return false;
}
number = result.AsDouble();
return true;
}
public void Dispose() => _expression.Dispose();
}Для base_damage * multiplier задайте имена base_damage, multiplier и значения 20.0, 1.25: результат 25. Повторная передача 2.0, 3.0 без Parse даёт 6. Адаптер отказывает при неверном числе входов, NaN/Infinity, нечисловом результате или ошибке вычисления.
Ограничения
1 / 2 с целыми литералами даёт целочисленный результат 0. Используйте вещественный операнд, если нужна дробь. Строки, массивы и другие Variant-значения не становятся числами автоматически в приведённом адаптере.
showError=false отключает печать обычной ошибки вычисления; её всё равно нужно обработать. Не вызывайте Execute после неуспешного Parse. constCallsOnly ограничивает вызовы методов объектов, но не превращает Expression в изолированную среду для произвольного чужого кода. В примере строка формулы задаётся разработчиком, а меняются числовые входы.