Flee (支持 Net6.0, Net5.0, Netstandard2.1, Netstandard2.0)
动态解析的框架是有几个的,个人先使用了DynamicExpresso,但是需求中是需要支持IF/ELSE的,DynamicExpresso中支持三目运算,可以代替IF/ELSE,需要对字符串表达式进行IF/ELSE到三目运算的转换才能使用,之后发现了Flee直接支持。
DynamicExpresso和Flee相比较,个人感觉Flee的性能更好,支持的功能也比较多。Flee支持自定函数,可以进行类的导入,其他变量等各个框架都有的功能就不详细说了。大家可以体验自行对比下。
Flee的用法都可以参照官网的demo进行使用,还是比较详细的。
在我项目中的场景是需要对表达式相同,但其中变量不同的表达式进行多次运算。
我这里大概需要循环2w次左右,有2w条数据需要计算
for (int i = 0; i < scurveFormulasSource.Count; i++)
{
ExpressionContext context = new ExpressionContext();
context.Imports.AddType(typeof(Math));
//赋值变量
foreach (var item in scurveFormulasSource[i])
{
context.Variables[item.Key.Replace("*", "")] = item.Value;
}
IGenericExpression<double> exp = context.CompileGeneric<double>(input.Text);
double result = Math.Round(exp.Evaluate(), 2);
}
这样计算大概需要4s
因为我每次的表达式是相同的,所以我想着可以用一个表达式,也就是IGenericExpression
这段代码提取出来,不参与循环,循环中只进行赋值。如下代码
ExpressionContext context = new ExpressionContext();
context.Imports.AddType(typeof(Math));
IGenericExpression<double> exp = context.CompileGeneric<double>(input.Text);
for (int i = 0; i < scurveFormulasSource.Count; i++)
{
//赋值变量
foreach (var item in scurveFormulasSource[i])
{
context.Variables[item.Key.Replace("*", "")] = item.Value;
}
double result = Math.Round(exp.Evaluate(), 2);
}
这样的代码运行后会报错,提示找不到我定义的变量,在GenericExpression
构建表达式的时候就会进行变量检查,如果没有表达式里的变量就会抛出异常。
我们可以做如下处理,在构建表达式之前先对变量进行赋值定义,之后再修改值 这样就不会抛出异常了。如下
ExpressionContext context = new ExpressionContext();
context.Imports.AddType(typeof(Math));
//赋值变量
foreach (var item in scurveFormulasSource[i])
{
context.Variables[item.Key.Replace("*", "")] = item.Value;
}
IGenericExpression<double> exp = context.CompileGeneric<double>(input.Text);
for (int i = 0; i < scurveFormulasSource.Count; i++)
{
//赋值变量
foreach (var item in scurveFormulasSource[i])
{
context.Variables[item.Key.Replace("*", "")] = item.Value;
}
double result = Math.Round(exp.Evaluate(), 2);
}
在获取表达式之前先定义出变量,之后修改值,这样修改后本次的运行时间为20毫秒左右。