我需要解决的问题是通过 IF 语句运行数据。IF 语句由运行时的 SQL 表生成。
我已经设法通过使用表达式和 Lambda 表达式来做到这一点。
我的表有 memberName;操作员; 目标。例如,我从表中得到“Age”、“GreaterThan”和“40”,然后编译它。
var rule = new Rule(rowRule["memberName"].ToString(), rowRule["Operator"].ToString(), rowRule["Target"].ToString());
Func<User, bool> compiledRule = CompileRule<User>(rule);
我得到一个真值或假值,它工作得很好。
public static Func<T, bool> CompileRule<T>(Rule r)
{
var paramUser = Expression.Parameter(typeof(User));
Expression expr = BuildExpr<T>(r, paramUser);
// build a lambda function User->bool and compile it
return Expression.Lambda<Func<T, bool>>(expr, paramUser).Compile();
}
static Expression BuildExpr<T>(Rule r, ParameterExpression param)
{
var left = MemberExpression.Property(param, r.MemberName);
var tProp = typeof(T).GetProperty(r.MemberName).PropertyType;
ExpressionType tBinary;
// is the operator a known .NET operator?
if (ExpressionType.TryParse(r.Operator, out tBinary))
{
var right = Expression.Constant(Convert.ChangeType(r.TargetValue, tProp));
// use a binary operation, e.g. 'Equal' -> 'u.Age == 15'
return Expression.MakeBinary(tBinary, left, right);
}
else
{
var method = tProp.GetMethod(r.Operator);
var tParam = method.GetParameters()[0].ParameterType;
var right = Expression.Constant(Convert.ChangeType(r.TargetValue, tParam));
// use a method call, e.g. 'Contains' -> 'u.Tags.Contains(some_tag)'
return Expression.Call(left, method, right);
}
}
这对于像“Age > 30”这样的简单 if 语句非常有用
但是现在我需要它更复杂,通过在 if 语句中嵌套计算,例如我需要处理像“Age > (30 / 2)”这样的语句
任何人都知道我如何调整我的规则引擎以进行计算。
如果我可以将从表中获得的目标值解析为代码并在方法中执行它并返回单个值然后创建规则,但我不确定如何在运行时获取字符串,解析为代码并执行它。
我走进了表达式树的兔子洞,以为这可能是我的答案,但我意识到表达式树只是一种可视数据结构,而不是执行的代码。
如果像这样的规则引擎已经存在,那就太好了,但我还没有真正看到过类似的东西。