用对象表示运算符前置的逻辑表达式,定义方式如下
//参数类型枚举
//类型为LogicExpr的Parameter对象,其Parm为一个QueryCondition对象
//类型为Property的Parameter对象,Parm为待判定的属性名
public enum ParameterType { LogicExpr, Property, Number, Str, DateTime, Boolean }
//参数类
public class Parameter
{
//参数类型
public ParameterType ParmType;
//参数值
public Object Parm;
public Parameter() { }
public Parameter(ParameterType parmType, Object parm)
{
this.ParmType = parmType;
this.Parm = parm;
}
}
//逻辑表达式类
public class QueryCondition
{
//逻辑运算符
//一元运算符:isNull,isNotNull,not(参数类型为LogicExpr)
//二元运算符:=,<>,>,>=,<,<=,like(规则同SQL)
//三元运算符:between(参数2<参数1<参数3的场合返回true)
//多元运算符:in,notIn(参数2...参数n的ParmType一致)
// and,or(所有参数ParmType均为LogicExpr)
public string Op;
//参数数组
public Parameter[] Parms;
}
例如对JSON串{"name":"John","age":10,"grade":3},建立QueryCondition对象如下:
QueryCondition condition = new QueryCondition();
QueryCondition condition1 = new QueryCondition();
QueryCondition condition2 = new QueryCondition();
condition.Op = "and";
condition.Parms[0] = new Parameter(ParameterType.LogicExpr, condition1);
condition.Parms[1] = new Parameter(ParameterType.LogicExpr, condition2);
condition1.Op = "<";
condition1.Parms[0] = new Parameter(ParameterType.Property, "age");
condition1.Parms[1] = new Parameter(ParameterType.Number, 30);
condition2.Op = "=";
condition2.Parms[0] = new Parameter(ParameterType.Property, "grade");
condition2.Parms[1] = new Parameter(ParameterType.Number, 3);
等同于判断 age<30 and grade=3 返回true
求教应采用怎样的方式完成QueryCondition的判定,暂不考虑对参数类型数量等合法性进行验证
------解决思路----------------------
1、把Json转换为object,可以用开源的Json.Net。具体可以调用JToken.Parse(string)。
2、判定QueryCondition,可以在QueryCondition类中,加一个Eval判定函数:
public class QueryCondition
{
//逻辑运算符
public string Op;
//参数数组
public Parameter[] Parms;
public object Eval(object context)
{
object[] parameters = Parms.Select(p => p.Eval(context)).ToArray();
object obj1 = parameters[0], obj2 = parameters.Length > 1 ? parameters[1] : null;
CoerceTypes(ref obj1, ref obj2);
switch (Op)
{
case "<":
return System.Collections.Comparer.Default.Compare(obj1, obj2) < 0;
case "=":
return object.Equals(obj1, obj2);
case "and":
return parameters.All(p => (p as bool?) == true);
}
throw new NotImplementedException(Op + " operator not implemented");
}
private static void CoerceTypes(ref object obj1, ref object obj2)
{
if (object.ReferenceEquals(obj1, null)
------解决思路----------------------
object.ReferenceEquals(obj2, null)) return;
TypeCode typecode1 = Type.GetTypeCode(obj1.GetType());
TypeCode typecode2 = Type.GetTypeCode(obj2.GetType());
if (typecode1 != TypeCode.Object && obj2 is IConvertible) obj2 = Convert.ChangeType(obj2, typecode1);
if (typecode2 != TypeCode.Object && obj1 is IConvertible) obj1 = Convert.ChangeType(obj1, typecode2);
}
}
3、Parameter转换也可以在Parameter类中,添加一个Eval函数:
public class Parameter
{
//...
public object Eval(object context)
{
switch(ParmType)
{
case ParameterType.Boolean:
return (bool) Parm;
case ParameterType.DateTime:
return (DateTime) Parm;
case ParameterType.LogicExpr:
if (Parm is bool
------解决思路----------------------
Parm is bool?) return Parm;
return (Parm as QueryCondition).Eval(context);
case ParameterType.Number:
return Convert.ToDouble(Parm);
case ParameterType.Property:
if (object.ReferenceEquals(context, null)) throw new ArgumentNullException("context");
var indexer = context.GetType().GetProperty("Item", new Type[] { typeof(string) });
if (indexer != null) return indexer.GetValue(context, new object[] { Parm });
return context.GetType().GetProperty(Parm as string).GetValue(context);
case ParameterType.Str:
return (string)Parm;
}
throw new NotImplementedException(ParmType + " parameter type not implemented");
}
}
这样,就可以对QueryCondition进行判定:
static void Main(string[] args)
{
QueryCondition condition = new QueryCondition();
QueryCondition condition1 = new QueryCondition();
QueryCondition condition2 = new QueryCondition();
condition.Op = "and";
condition.Parms = new Parameter[]
{
new Parameter(ParameterType.LogicExpr, condition1),
new Parameter(ParameterType.LogicExpr, condition2),
};
condition1.Op = "<";
condition1.Parms = new Parameter[]
{
new Parameter(ParameterType.Property, "age"),
new Parameter(ParameterType.Number, 30),
};
condition2.Op = "=";
condition2.Parms = new Parameter[]
{
new Parameter(ParameterType.Property, "grade"),
new Parameter(ParameterType.Number, 3),
};
string json = "{'name':'John','age':10,'grade':3}";
bool result = (bool)condition.Eval(JToken.Parse(json)); // result = true
}