Para o pessoal que trabalha com .Net, existe a biblioteca [Flee].(https://github.com/mparlak/Flee)
Ela é sensacional, permite resolver expressões em tempo de execução além de permitir ser estendida, criando suas próprias funções personalizadas.
- Resolvendo expressões:
using Flee.PublicTypes;
public class DynamicExpressions
{
private readonly ExpressionContext expressionContext = new();
public DynamicExpressions()
{
// Exemplo de inclusão de funções customizadas
expressionContext.Imports.AddType(typeof(CustomFunctions));
// Inclusão da System.Math, para permitir utilizar todos os seus métodos
expressionContext.Imports.AddType(typeof(Math), "Math");
//Configurações de regionalidade
expressionContext.ParserOptions.DecimalSeparator = '.';
expressionContext.ParserOptions.FunctionArgumentSeparator = ',';
expressionContext.ParserOptions.RecreateParser();
}
/// <summary>
/// Recebe uma expressão booleana em formato string e retorna o resultado
/// </summary>
/// <param name="expression"></param>
/// <returns></returns>
public bool EvaluateBoolExpression(string expression)
{
bool result;
try
{
IGenericExpression<bool> e = expressionContext.CompileGeneric<bool>(expression);
result = e.Evaluate();
}
catch (Exception ex)
{
throw new Exception("Erro ao validar a expressão booleana: (" + expression + ") - '" + ex.Message + "'");
}
return result;
}
/// <summary>
/// Recebe uma expressão matemática em formato string e retorna o resultado
/// </summary>
/// <param name="expression"></param>
/// <returns></returns>
public double EvaluateDoubleExpression(string expression)
{
double result;
try
{
// Exemplo de utilização de método da System.Math
// double valorArredondado = expressionContext.CompileGeneric<double>("Math.Round(1.55540040, 2)").Evaluate();
// Exemplos de utilização de método personalizado
//Arredonda(
// 3.0 * MaiorValor(10.90 - 5.0, 0.0) + (10.0 + 15.0 + 20.0)
//, 2)
//double somaArray = expressionContext.CompileGeneric<double>("Soma(1.5, 2, 3, 4, 5, 6)").Evaluate();
//double valorArredondadoAbnt5891 = expressionContext.CompileGeneric<double>("ArredondaAbnt5891(1.55540040, 2)").Evaluate();
IGenericExpression<double> e = expressionContext.CompileGeneric<double>(expression);
result = e.Evaluate();
}
catch (Exception ex)
{
throw new Exception("Erro ao validar a expressão matemática: (" + expression + ") - '" + ex.Message + "'");
}
return result;
}
}
- Estendendo:
/// <summary>
/// Funções personalizadas
/// Todos os métodos incluídos nesta classe, estarão disponíveis para uso nas expressoes
/// </summary>
public static class CustomFunctions
{
/// <summary>
/// Método de arredondamento "round-half-even"
/// Ou "arredondamento do banqueiro"
/// </summary>
/// <param name="value"></param>
/// <param name="digits"></param>
/// <returns></returns>
public static double ArredondaAbnt5891(double value, int digits)
{
return Math.Round(value, digits, MidpointRounding.ToEven);
}
/// <summary>
/// Método de arredondamento "AwayFromZero"
/// </summary>
/// <param name="value"></param>
/// <param name="digits"></param>
/// <returns></returns>
public static double Arredonda(double value, int digits)
{
return Math.Round(value, digits, MidpointRounding.AwayFromZero);
}
/// <summary>
/// Executa a soma de todos os itens do array de doubles
/// </summary>
/// <param name="valores"></param>
/// <returns></returns>
public static double Soma(params double[] valores)
{
double resultado = 0;
for (int i = 0; i < valores.Length; i++)
{
resultado += valores[i];
}
return resultado;
}
}