C# 实现自定义表达式
最近遇到一个问题,希望程序可以支持自定义表达式的计算,
比如A(p1) & B(p2,p3) || C()
,计算这个表达式是true还是false,进而去完成其他工作
而到运行到这里的时候,程序才会知道具体的表达式是什么,表达式和参数是通过定义表达式的数据传进来的,是不固定的
数据结构类似
internal class CustomCondition
{
internal MethodTypeEnum MethodType { get; set; }
internal ConnectionTypeEnum ConnectionType { get; set; }
internal object Value { get; set; }
}
internal enum MethodTypeEnum
{
Method1,
Method2,
}
internal enum ConnectionTypeEnum
{
Add,
Or
}
这里没有加(),实际上也可能有括号,比如(A(p1) && B(p2,p3)) || C() && D(p4)
我最开始做的版本,是把每一个方法的结果算出来,然后再根据 && 和 || 做运算,最后得到结论,
但实际上,并不是每一个方法都需要被运算,才能得到表达式的结果
比如,A() || B()
,当计算A()为true时,表达式结果就是true,不必再计算B()方法了
解决这个问题,能用到C#的短路模式是最佳的,
一开始我的思路是通过表达式树来实现,但是因为条件可能会很复杂,调研之后觉得要写的代码太多了,Debug也会很麻烦,
最后选择了一个第三方库DynamicExpresso
阅读README可知,通过“拼接”表达式,传入参数的方式,可以快速实现目标
关键代码如下
List<CustomCondition> customConditions = new List<CustomCondition>();
customConditions.Add(new CustomCondition() { MethodType = MethodTypeEnum.Method2, ConnectionType = ConnectionTypeEnum.Or, Value = 0 });
customConditions.Add(new CustomCondition() { MethodType = MethodTypeEnum.Method1, ConnectionType = ConnectionTypeEnum.Or, Value = "not null" });
bool result = false;
string expressionText = "";
List<Parameter> parameters = new List<Parameter>();
int index = 0;
foreach (CustomCondition condition in customConditions)
{
var parameterName = $"parameter{index}";
switch (condition.MethodType)
{
case MethodTypeEnum.Method1:
expressionText += $"{nameof(Method1)}({parameterName}) {GetConnectionType(condition.ConnectionType)} ";
parameters.Add(new Parameter(parameterName, typeof(string), (string)condition.Value));
break;
case MethodTypeEnum.Method2:
expressionText += $"{nameof(Method2)}({parameterName}) {GetConnectionType(condition.ConnectionType)} ";
parameters.Add(new Parameter(parameterName, typeof(int), (int)condition.Value));
break;
default:
throw new Exception("错误的MethodType");
}
index++;
}
expressionText = expressionText.Remove(expressionText.Length - 3);
var target = new Interpreter().SetFunction(nameof(Method1), Method1).SetFunction(nameof(Method2), Method2);
var r3 = target.Eval<bool>(expressionText, parameters.ToArray());
示例代码
学习技术最好的文档就是【官方文档】,没有之一。
还有学习资料【Microsoft Learn】、【CSharp Learn】、【My Note】。
如果,你认为阅读这篇博客让你有些收获,不妨点击一下右下角的【推荐】按钮。
如果,你希望更容易地发现我的新博客,不妨点击一下【关注】。