Expression表达式树--无聊写了个表达式树的小轮子用于日常使用

在刚开始敲代码的时候遇到过这样的事:查询条件多,查询条件不唯一,这个时候需要我们去写非常多的if-else 以及在where写冗长的lamada式

这时候我们可以通过Expression构建动态表达式树来生成所谓的lamada表达式

附上教程;https://ldqk.xyz/1795?kw=%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%A0%91

public class Student
    {
        [Expression(Wheretype.Equal,Logictype.And)]
        public string Banji { get; set; }
        [Expression(Wheretype.Equal, Logictype.And)]
        public string id { get; set; }
        [Expression(Wheretype.Like, Logictype.And)]
        public string name { get; set; }
        [Expression(Wheretype.Equal, Logictype.And)]
        public string url { get; set; }
        [Expression(Wheretype.Equal, Logictype.And)]
        public string txtName { get; set; }

        public static string Sayname(string name) {
            return "我叫" + name;
        }
    }

自定义特性

点击查看代码
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Enum|AttributeTargets.Property)]
    public class ExpressionAttribute:Attribute
    {
        public  Logictype logictype{ get; set; }//And 0r
        public  Wheretype ExpressionName { get { return expre; } }//Equeal、Like
        private Wheretype expre { get; set; }
        public ExpressionAttribute(Wheretype wheretype,Logictype logictype1) {
            expre = wheretype;
            logictype = logictype1;
        }
        public int SwitchType() {
            if (expre == Wheretype.Equal && logictype == Logictype.And)
                return 1;
            if (expre == Wheretype.Equal && logictype == Logictype.Or)
                return 2;
            if (expre == Wheretype.Like && logictype == Logictype.And)
                return 3;
            if (expre == Wheretype.Like && logictype == Logictype.Or)
                return 4;
            return 0;
        }
    }

    public enum Wheretype
    {
        Equal,
        Like
    }

    public enum Logictype
    {
        And,
        Or
    }

构建的表达式树泛型类

点击查看代码
public class ExpressionBuilder<TEntity>
    {
        private ParameterExpression para;
        private TEntity entity1;
        public ExpressionBuilder(TEntity entity){
            para = Expression.Parameter(typeof(TEntity),"T");
            this.entity1 = entity;
        }

        public BinaryExpression whereAlso =Expression.And(Expression.Constant(true),Expression.Constant(true));
        public Expression Equal(string filed)
        {
            var value= GetVlaue(filed);
            if (value == null)
                return null;
            var prop = Expression.Property(para, filed);
            var eq = Expression.Equal(prop, Expression.Constant(value, value.GetType()));
            return eq;
        }
        public Expression LessThan(string filed)
        {
            var value = GetVlaue(filed);
            if (value is null)
                return null;
            var prop = Expression.Property(para, filed);
            var lessthan = Expression.LessThan(prop, Expression.Constant(value));
            return lessthan;
        }
        public Expression MoreThan(string filed)
        {
            var value = GetVlaue(filed);
            if (value is null)
                return null;
            var prop = Expression.Property(para, filed);
            var morethan = Expression.GreaterThan(prop, Expression.Constant(value));
            return morethan;
        }
        public Expression MoreThanEqual(string filed)
        {
            var value = GetVlaue( filed);
            if (value is null)
                return null;
            var prop = Expression.Property(para, filed);
            var morethan = Expression.GreaterThanOrEqual(prop, Expression.Constant(value));
            return morethan;
        }
        public Expression Like(string filed)
        {
            var value = GetVlaue(filed);
            if (value == null)
                return null;
            var prop = Expression.Property(para,filed);
            var method = typeof(String).GetMethod("Contains", new[] { typeof(string) });
            var call = Expression.Call(prop, method, Expression.Constant(value));
            return call;
        }
        /// <summary>
        /// 获取实体属性值
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="filed"></param>
        /// <returns></returns>
        public object GetVlaue(string filed) {
            var props = typeof(TEntity).GetProperties();
            if (!props.Select(p => p.Name).ToList().Contains(filed))
                return null;
            return props.Where(p => p.Name == filed).FirstOrDefault().GetValue(this.entity1);
        }
        public void And(Expression bianEx) {
            if (bianEx != null)
                this.whereAlso = Expression.AndAlso(whereAlso, bianEx);
        }
        /// <summary>
        /// 创建lamada委托表达式
        /// </summary>
        /// <returns></returns>
        public Expression<Func<TEntity,bool>> CreateLamada()
        {
            if (this.whereAlso != null)
                return Expression.Lambda<Func<TEntity, bool>>(this.whereAlso, para);
            return null;
        }
        public void Or(Expression expression) {
            if (expression != null)
                this.whereAlso = Expression.OrElse(this.whereAlso, expression);
        }
        /// <summary>
        /// 全匹配
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public Expression<Func<TEntity, bool>> Catchall()
        {
            ParameterExpression para = Expression.Parameter(typeof(TEntity), "t");
            if (this.entity1 == null)
                return null;
            BinaryExpression whereExpression = Expression.And(Expression.Constant(true), Expression.Constant(true));
            var props = typeof(TEntity).GetProperties();
            Expression expre = null;
            foreach (var item in props)
            {
                if (item.GetValue(this.entity1) is null)//过滤空值属性
                    continue;
                var attr = item.GetCustomAttributes().ToArray()[0] as ExpressionAttribute;
                var prop = Expression.Property(para, item.Name);
                var method = typeof(String).GetMethod("Contains", new[] { typeof(string) });
                switch (attr.SwitchType()) {
                    case 1:
                        expre= Expression.Equal(prop, Expression.Constant(item.GetValue(this.entity1)));
                        whereExpression = Expression.And(whereExpression, expre);
                        break;
                    case 2:
                        expre = Expression.Equal(prop, Expression.Constant(item.GetValue(this.entity1)));
                        whereExpression = Expression.Or(whereExpression, expre);
                        break;
                    case 3:
                        expre = Expression.Call(prop, method, Expression.Constant(GetVlaue(item.Name)));
                        whereExpression = Expression.And(whereExpression, expre);
                        break;
                    case 4:
                        expre = Expression.Call(prop, method, Expression.Constant(GetVlaue(item.Name)));
                        whereExpression = Expression.Or(whereExpression, expre);
                        break;
                }
            }
            return Expression.Lambda<Func<TEntity, bool>>(whereExpression, para);
        }

        public Expression In( string filed, string[] objects) {
            var prop = Expression.Property(para,filed);
            var contains = typeof(Enumerable).GetMethods().FirstOrDefault(p => p.GetParameters().Length == 2 && p.Name == "Contains").MakeGenericMethod(typeof(string));
            var call = Expression.Call(null, contains,Expression.Constant(objects), prop);
            return call;
        }
    }

数据测试

Student stu = new Student() { id = "15", name = "s" };//x=>x.id=="15"&&x.name.Contains("s")
            ExpressionBuilder<Student> eb = new ExpressionBuilder<Student>(stu);
            Console.WriteLine(eb.Catchall());
            //eb.And(eb.In("id", "17,15".Split(',')));
            //var lamada = eb.CreateLamada();
            //Console.WriteLine(lamada);
            var list = stus.AsQueryable().Where(eb.Catchall()).ToList();
            Console.WriteLine("筛选之前的数据");
            foreach (var item in stus)
            {
                Console.WriteLine(item.id + "   " + item.name);
            }
            Console.WriteLine("筛选之后的数据");
            foreach (var item in list)
            {
                Console.WriteLine(item.id + "   " + item.name);
            }

结果如图

用表达式树构建的In:p=>"15,17".Split(",").Contains(p.id)

Student stu = new Student() { id = "15", name = "s" };//x=>x.id=="15"&&x.name.Contains("s")
            ExpressionBuilder<Student> eb = new ExpressionBuilder<Student>(stu);
            Console.WriteLine(eb.Catchall());
            eb.And(eb.In("id", "17,15".Split(',')));
            var lamada = eb.CreateLamada();
            var list = stus.AsQueryable().Where(lamada).ToList();

结果如图

最后:如有不足请多指教

 

posted @ 2021-10-23 16:08  布吉岛1c  阅读(136)  评论(4编辑  收藏  举报