当前位置: 代码迷 >> C# >> 前置运算符逻辑表达式的判定(参看代码)
  详细解决方案

前置运算符逻辑表达式的判定(参看代码)

热度:325   发布时间:2016-05-05 05:04:30.0
前置运算符逻辑表达式的判定(参见代码)
用对象表示运算符前置的逻辑表达式,定义方式如下

    //参数类型枚举
    //类型为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
}
  相关解决方案