三方库
RulesEngine
rule字段
| 字段 | 用途 | 场景示例 |
|---|---|---|
RuleName |
规则标识 | "HighTemperatureWarning" |
Expression |
判断条件 | telemetry.Temperature > 40 |
SuccessEvent |
成功时返回 | "TEMP_WARNING" |
ErrorMessage |
失败信息 | "传感器读数异常" |
Actions |
后置动作 | 启动空调、发送短信 |
LocalParams |
中间变量 | 计算变化率、平均值 |
lambda表达式
语法上就是动态LINQ。
表达式传参:
c#
ruleDefinitions.Add(new Rule
{
RuleName = "rule1",
Expression = "$v > $threshold",
ErrorMessage = "Value must be less than $threshold",
SuccessEvent = "error"
});
// 准备输入数据
RuleParameter[] input = [new("$v", 50), new("$threshold", 40)];
// 执行规则检查
var results = await rulesEngine.ExecuteAllRulesAsync("AlarmRules", input);
RuleEngine编译规则表达式的关键逻辑在namespace RulesEngine.ExpressionBuilders的RuleExpressionParser.cs的Parse函数里:
c#
public Expression Parse(string expression, ParameterExpression[] parameters, Type returnType)
{
ParsingConfig parsingConfig = new ParsingConfig()
{
CustomTypeProvider = (IDynamicLinqCustomTypeProvider) new CustomTypeProvider(this._reSettings.CustomTypes),
IsCaseSensitive = this._reSettings.IsExpressionCaseSensitive
};
try
{
// 这个ExpressionParser就是System.Linq.Dynamic.Core库里解析动态LINQ的解析器
return new ExpressionParser(parameters, expression, Array.Empty<object>(), parsingConfig).Parse(returnType);
}
catch (ParseException ex)...
规则表达式的校验
规则表达式实际上是一个动态LINQ,可使用System.Linq.Dynamic.Core库的DynamicExpressionParser.ParseLambda来校验,该函数最终也会调用ExpressionParser.Parse来解析规则字符串:
c#
public static LambdaExpression ParseLambda(
Type? delegateType,
ParsingConfig? parsingConfig,
bool createParameterCtor,
ParameterExpression[] parameters,
Type? resultType,
string expression,
params object?[]? values)
{
...
ExpressionParser expressionParser = new ExpressionParser(parameters, expression, values, parsingConfig);
Expression expression1 = expressionParser.Parse(resultType, createParameterCtor);
//如果是lambda表达式,则返回
if (expression1 is LambdaExpression lambda)
return lambda;
if (parsingConfig != null && parsingConfig.RenameParameterExpression && parameters.Length == 1)
{
ParameterExpression parameterExpression;
Expression body = new ParameterExpressionRenamer(expressionParser.LastLambdaItName).Rename(expression1, out parameterExpression);
return !(delegateType == (Type) null) ? Expression.Lambda(delegateType, body, parameterExpression) : Expression.Lambda(body, parameterExpression);
}
// 如果不是,构造一个lambda表达式返回
return !(delegateType == (Type) null) ? Expression.Lambda(delegateType, expression1, parameters) : Expression.Lambda(expression1, parameters);
}
lambda表达式与C#语法的差异
基本上与C#语法是类似的,但由于动态LINQ是单独解析的(而不是用C#的Roslyn编译器),所以还是有些区别,目前发现的:
- double类型也能进行位操作,而这一点在C#里编译都不过,原因是动态LINQ会自动把double截断为整型。
- 类型转换用int(v),而不像C#里那样(int)v
IMemoryCache组件
过期策略
| 策略类型 | 说明 | 适用场景 |
|---|---|---|
| 绝对过期 | 固定时间点过期 | 数据在特定时间后失效(如整点更新) |
| 相对过期 | 从缓存写入开始计时 | 数据在一段时间后失效 |
| 滑动过期 | 每次访问重置计时器 | 热点数据,长时间不访问则清除 |
| 组合策略 | 绝对+滑动同时使用 | 保证最终过期 + 活跃续期 |
| 优先级 | 内存压力时优先清除 | 缓存驱逐时的权重控制 |
全局性
IMemoryCache是ASP.NET里的singleton服务,相当于一个全局字典,因此字典key的选择必须带上业务或租户隔离字段。