我正在尝试用c#构建一个规则引擎,用户可以在其中定义JSON格式的规则,然后在运行时将其编译成C#代码。我正在关注这篇文章
http://coding-time.blogspot.com/2011/07/how-to-implement-rule-engine-in-c.html
一切都很正常,但这个规则引擎似乎只适用于和条件。我找不到任何方法来设置OR条件。
下面是我的代码:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
public class Program
{
public class ProductFamily
{
public int MotorHP
{
get;
set;
}
public String StationType
{
get;
set;
}
}
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("Contains",new[] { typeof(string) });
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);
}
}
public static void Main()
{
string json = File.ReadAllText(@"TextFile1.txt");
RulesManager ruleManagerObj = JsonConvert.DeserializeObject<RulesManager>(json);
//List<Rule> rulesObj = new List<Rule>
//{
// new Rule("MotorHP", "GreaterThan", "20"),
// new Rule("StationType", "Equal", "Horizontal Centrifugal")
//};
//RulesManager ruleObj = new RulesManager()
//{
// rules = rulesObj,
// Message = "Test Failed!"
//};
var productFamily1 = new ProductFamily
{
MotorHP = 21,
StationType = "Horizontal Cfugall"
}
;
var productFamily2 = new ProductFamily
{
MotorHP = 21,
}
;
var productFamily3 = new ProductFamily
{
MotorHP = 13,
};
//var rule = new Rule("MotorHP", "GreaterThan", "20");
//Func<ProductFamily, bool> compiledRule = CompileRule<ProductFamily>(rule);
//bool isMatch = compiledRule(productFamily1);
// Compile all the rules once.
var compiledRules = ruleManagerObj.rules.Select(r => CompileRule<ProductFamily>(r)).ToList();
if (!compiledRules.Any(rule => rule(productFamily1)))
Console.WriteLine(ruleManagerObj.Message);
Console.ReadLine();
}
public static Func<T, bool> CompileRule<T>(Rule r)
{
var param = Expression.Parameter(typeof(ProductFamily));
Expression expr = BuildExpr<T>(r, param);
// build a lambda function User->bool and compile it
return Expression.Lambda<Func<T, bool>>(expr, param).Compile();
}
public class RulesManager
{
//Func<ProductFamily, Boolean> Matches { get; set; }
public List<Rule> rules { get; set; }
public Level Level { get; set; } // Level is an enum
public string Message { get; set; }
}
public class Rule
{
public string MemberName
{
get;
set;
}
public string Operator
{
get;
set;
}
public string TargetValue
{
get;
set;
}
public Rule(string MemberName, string Operator, string TargetValue)
{
this.MemberName = MemberName;
this.Operator = Operator;
this.TargetValue = TargetValue;
}
}
public enum Level
{
Error = 1
}
}Json字符串:
{
"rules": [
{
"MemberName": "MotorHP",
"Operator": "GreaterThan",
"TargetValue": "20"
},
{
"MemberName": "StationType",
"Operator": "Contains",
"TargetValue": "Horizontal Centrifugal"
}
],
"Level": 1,
"Message": "Test Failed!"
}在计算表达式或规则时,有没有办法添加OR条件或条件的组合。
示例:
(rule1 && rule2 && ... ruleN) && (rule1 || rule2 || ... ruleM)发布于 2021-06-22 02:15:05
您可以使用Expression.AndAlso和Expression.OrElse。
因此,例如,表达式(rule1 && rule2) && (rule3 || rule4 || rule5)将构造为:
Expression.AndAlso(
Expression.AndAlso(rule1, rule2),
Expression.OrElse(Expression.OrElse(rule3, rule4), rule5)
);https://stackoverflow.com/questions/68070463
复制相似问题