表达式目录树学习笔记

表达式目录树学习笔记

第一堂课:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;//表达式目录树的命名空间
using System.Text;
using System.Threading.Tasks;

namespace 表达式目录树
{
    class Program
    {
        static void Main(string[] args)
        {
            ExpressionShow();
            Console.ReadKey();
        }

        #region 表达式目录树1
        static void ExpressionShow()
        {
            //委托和表达式目录树的区别
            {
                Func<int, int, int> func = (m, n) => m * n + 2;//实际为:new Func<int,int,int>((m,n)=>m*n+2);
                Expression<Func<int, int, int>> expression = (m, n) => m * n + 2;//Lambda表达式声明表达式目录树
                //Expression<Func<int,int,int>> expression1=(m,n)=>
                //{
                //    return m * n + 2;
                //}

                //表达式目录树:语法树,或者说是一种数据结构
                int iResult1 = func.Invoke(12, 12);
                int iResult2 = expression.Compile().Invoke(12, 12);//可以编译为委托后使用Invoke
            }

            //上面的Lambda是快捷生成表达式目录树的方式
            //Queryable传递的是表达式目录树

            {
                Expression<Func<int, int, int>> expression = (m, n) => m * n + 2;

                ParameterExpression parameterExpression = Expression.Parameter(typeof(int), "m");
                ParameterExpression parameterExpression2 = Expression.Parameter(typeof(int), "n");
                var multiply = Expression.Multiply(parameterExpression, parameterExpression2);
                var constant = Expression.Constant(2, typeof(int));
                var add = Expression.Add(multiply, constant);
                Expression<Func<int, int, int>> myExpression = Expression.Lambda<Func<int, int, int>>(add,
                    new ParameterExpression[]
                {
                    parameterExpression,
                    parameterExpression2
                });
                int iResult = myExpression.Compile().Invoke(11, 12);
                int iResult1 = myExpression.Compile()(11, 12);//myExpression.Compile()是一个委托,所以也可以这样执行表达式目录树
            }

            //自己拼装表达式目录树
            {
                //常量
                ConstantExpression conLeft = Expression.Constant(345);
                ConstantExpression conRight = Expression.Constant(456);
                BinaryExpression binary = Expression.Add(conLeft, conRight);//345+456
                Expression<Action> actExpression = Expression.Lambda<Action>(binary, null);//null表示参数为空
                //只能执行表示Lambda表达式的表达式目录树,即LambdaExpression或者Expression<TDelegate>类型
                actExpression.Compile()();//()=>345+456
            }
            {
                Console.WriteLine("变量表达式目录树");
                ParameterExpression paraLeft = Expression.Parameter(typeof(int), "a");
                ParameterExpression paraRight = Expression.Parameter(typeof(int), "b");
                BinaryExpression binaryLeft = Expression.Multiply(paraLeft, paraRight);
                ConstantExpression conRight = Expression.Constant(2, typeof(int));
                BinaryExpression binaryBody = Expression.Add(binaryLeft, conRight);

                Expression<Func<int, int, int>> lambda = Expression.Lambda<Func<int, int, int>>(binaryBody, paraLeft, paraRight);
                Console.WriteLine(lambda.Compile()(3, 4));
                Func<int, int, int> func = lambda.Compile();
                Console.WriteLine(func(3, 4));
            }
            {
                //Lambda方式创建表达式目录树
                Expression<Func<People, bool>> lambda = x => x.Id.ToString().Equals("5");
                //自定义拼凑表达式目录树
                ParameterExpression parameterExpression = Expression.Parameter(typeof(People), "x");
                var field = Expression.Field(parameterExpression, typeof(People).GetField("Id"));
                var toString = typeof(People).GetMethod("ToString");
                var toStringCall = Expression.Call(field, toString, new Expression[0]);
                var equals = typeof(People).GetMethod("Equals");
                var constant = Expression.Constant("5", typeof(string));
                var equalsCall = Expression.Call(toStringCall, equals, new Expression[] { constant });
                Expression<Func<People, bool>> expression =
                    Expression.Lambda<Func<People, bool>>(equalsCall, new ParameterExpression[]
                {
                    parameterExpression
                });
                expression.Compile().Invoke(new People()
                {
                    Id = 11,
                    Name = "Cgc",
                    Age = 28
                });
            }
            //数据库以前用户拼接条件
            {
                string sql = "SELECT * From USER WHERE 1=1";
                string name = "Cgc";
                if (string.IsNullOrWhiteSpace(name))
                {
                    sql += $"and name like '%{name}%'";//应该参数化,否则会被SQL注入
                }
            }

            //现在entity framework查询的时候,需要一个表达式目录树
            IQueryable<int> list = null;
            //都不过滤
            if (true)//只过滤A
            {
                Expression<Func<People, bool>> exp1 = x => x.Id > 1;
            }
            if (true)//只过滤B 
            {
                Expression<Func<People, bool>> exp2 = x => x.Age > 10;
            }

            //都过滤
            Expression<Func<People, bool>> exp3 = x => x.Id > 1 && x.Age > 10;
            //list.Where();

            {
                //硬编码:性能最佳
                People people = new People()
                {
                    Id = 11,
                    Name = "cgc",
                    Age = 29
                };
                PeopleCopy peopleCopy = new PeopleCopy()
                {
                    Id = people.Id,
                    Name = people.Name,
                    Age = people.Age
                };
                //以上写死了,只能为这两个类型服务
                //采用反射:不同类型都可以实现,
                {
                    var test = ReflectionMapper.Trans<People, PeopleCopy>(people);
                }
                {
                    //序列化器,
                    
                }
                {
                    //通用,性能高
                    //能不能动态生成硬编码,缓存起来
                    //第一次执行时需要一定实际实现硬编码,然后存储在静态字典中
                    var result=ExpressionMapper.Trans<People, PeopleCopy>(people);
                }
                {
                    //第二次执行时效率很高,因为第一次已经实现了硬编码
                    var result = ExpressionMapper.Trans<People, PeopleCopy>(people);
                }
                {
                    //泛型缓存:第一次执行时需要通过表达式目录树构建委托
                    var result = ExpressionGenericMapper<People, PeopleCopy>.Trans(people);
                }
                {
                    //第二次进入的时候两个类型没有变化则直接返回委托,不需要再构建委托的过程
                    var result = ExpressionGenericMapper<People, PeopleCopy>.Trans(people);
                }
                //总结:表达式目录树动态生成的用途
                //可以用来替代反射,因为反射可以通用,但是性能不够
                //可以生成硬编码,可以提升性能
            }
        }
        #endregion
    }

    public class People
    {
        public int Id;
        public string Name { get; set; }
        public int Age { get; set; }
    }

    public class PeopleCopy
    {
        public int Id;
        public string Name { get; set; }
        public int Age { get; set; }
    }

    /// <summary>
    /// 反射匹配
    /// </summary>
    public class ReflectionMapper
    {
        /// <summary>
        /// 利用反射匹配两个类的属性和字段
        /// </summary>
        /// <typeparam name="TIn"></typeparam>
        /// <typeparam name="TOut"></typeparam>
        /// <param name="tIn"></param>
        /// <returns></returns>
        public static TOut Trans<TIn,TOut>(TIn tIn)
        {
            TOut tOut = Activator.CreateInstance<TOut>();
            //属性
            foreach(var itemOut in tOut.GetType().GetProperties())
            {
                var propIn = tIn.GetType().GetProperty(itemOut.Name);
                itemOut.SetValue(tOut, propIn.GetValue(tIn));
            }
            //字段
            foreach(var itemOut in tOut.GetType().GetFields())
            {
                var propIn = tIn.GetType().GetField(itemOut.Name);
                itemOut.SetValue(tOut, propIn.GetValue(tIn));
            }
            return tOut;
        }
    }

    /// <summary>
    /// 静态字典
    /// </summary>
    public class ExpressionMapper
    {
        //静态字典:全局唯一,静态字典缓存
        private static Dictionary<string, object> _Dic = new Dictionary<string, object>();

        public static TOut Trans<TIn,TOut>(TIn tIn)
        {
            string key = string.Format("funckey_{0}_{1}", typeof(TIn).FullName, typeof(TOut).FullName);
            if(!_Dic.ContainsKey(key))
            {
                ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
                List<MemberBinding> memberBindingList = new List<MemberBinding>();
                //绑定属性
                foreach(var item in typeof(TOut).GetProperties())
                {
                    MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
                    MemberBinding memberBinding = Expression.Bind(item, property);
                    memberBindingList.Add(memberBinding);
                }
                //绑定字段
                foreach(var item in typeof(TOut).GetFields())
                {
                    MemberExpression field = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name));
                    MemberBinding memberBinding = Expression.Bind(item, field);
                    memberBindingList.Add(memberBinding);
                }
                MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
                Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[] { parameterExpression });
                Func<TIn, TOut> func = lambda.Compile();//拼装是一次性的
                _Dic[key] = func;
            }
            return ((Func<TIn, TOut>)_Dic[key]).Invoke(tIn);
        }
    }

    /// <summary>
    /// 泛型缓存:编译时确定
    /// </summary>
    /// <typeparam name="TIn"></typeparam>
    /// <typeparam name="TOut"></typeparam>
    public class ExpressionGenericMapper<TIn,TOut>
    {
        private static Func<TIn, TOut> _FUNC = null;
        static ExpressionGenericMapper()
        {
            ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
            List<MemberBinding> memberBindingList = new List<MemberBinding>();
            //绑定属性
            foreach (var item in typeof(TOut).GetProperties())
            {
                MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
                MemberBinding memberBinding = Expression.Bind(item, property);
                memberBindingList.Add(memberBinding);
            }
            //绑定字段
            foreach (var item in typeof(TOut).GetFields())
            {
                MemberExpression field = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name));
                MemberBinding memberBinding = Expression.Bind(item, field);
                memberBindingList.Add(memberBinding);
            }
            MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
            Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[] { parameterExpression });
            _FUNC = lambda.Compile();//拼装是一次性的
        }
        public static TOut Trans(TIn t)
        {
            return _FUNC(t);
        }
    }
}

第二堂课:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace 表达式目录树2
{
    class Program
    {
        static void Main(string[] args)
        {
            Show();
            Console.ReadKey();
        }

        private static int Get(int k)
        {
            return k * k;
        }

        public static void Show()
        {
            //ExpressionVisitor肯定是采用递归解析表达式目录树,因为不知道深度的一棵树
            //只有一个入口叫Visit
            //首先检查是个什么类型的表达式,然后调用对应的protect virtual visit方法
            //得到结果继续去检查类型--调用对应的visit方法--再检查--再调用
            //修改表达式目录树
            {
                Expression<Func<int, int, int>> exp = (m, n) => m * n + 2 + Get(5);
                //修改为m*n-2
                OperationsVisitor oVisitor = new OperationsVisitor();
                Expression exp2 = oVisitor.Modify(exp);
            }
            //利用表达式目录树拼接Sql语句
            {
                var source = new List<People>().AsQueryable();//DbSet
                var result=source.Where<People>(P => P.Age > 25);//SELECT * FROM People Where Age>25
                Expression<Func<People, bool>> lambda = x => x.Age > 25;
                ConditionBuilderVisitor visitor = new ConditionBuilderVisitor();
                visitor.Visit(lambda);
                Console.WriteLine(visitor.Condition());

            }
            {
                //ORM 把数据库映射到程序内存,通过操作对象来完成数据库的管理
                //屏蔽数据库,开发者完全不需要知道数据库

                Expression<Func<People, bool>> lambda = x => x.Age > 5 && x.Id > 5
                && x.Name.StartsWith("1") && x.Name.EndsWith("1") && x.Name.Contains("1");

                string sql = string.Format("Delete From [{0}] WHERE {1}",
                    typeof(People).Name, "[Age]>5 AND [ID]>5");

                ConditionBuilderVisitor visitor = new ConditionBuilderVisitor();
                visitor.Visit(lambda);
                Console.WriteLine(visitor.Condition());

            }
            {
                Expression<Func<People, bool>> lambda = x => x.Age > 5 && x.Name == "A" || x.Id > 5;
                ConditionBuilderVisitor visitor = new ConditionBuilderVisitor();
                visitor.Visit(lambda);
                Console.WriteLine(visitor.Condition());
            }
            {
                Expression<Func<People, bool>> lambda = x => x.Age > 5 || (x.Name == "A" && x.Id > 5);
                ConditionBuilderVisitor visitor = new ConditionBuilderVisitor();
                visitor.Visit(lambda);
                Console.WriteLine(visitor.Condition());
            }
            {
                Expression<Func<People, bool>> lambda = x => (x.Age > 5 || x.Name == "A") && x.Id > 5;
                ConditionBuilderVisitor visitor = new ConditionBuilderVisitor();
                visitor.Visit(lambda);
                Console.WriteLine(visitor.Condition());
            }
            #region 表达式链接
            {
                Expression<Func<People, bool>> lambda1 = x => x.Age > 5;
                Expression<Func<People, bool>> lambda2 = x => x.Id > 5;
                Expression<Func<People, bool>> lambda3 = lambda1.And(lambda2);
                Expression<Func<People, bool>> lambda4 = lambda1.Or(lambda2);
                Expression<Func<People, bool>> lambda5 = lambda1.Not();
                Do1(lambda3);
                Do1(lambda4);
                Do1(lambda5);
            }
            #endregion
        }

        private static void Do1(Func<People,bool> func)
        {
            List<People> people = new List<People>();
            people.Where(func);
        }


        private static void Do1(Expression<Func<People,bool>> func)
        {
            List<People> people = new List<People>()
            {
                new People(){Id=4,Name="123",Age=4},
                new People(){Id=5,Name="234",Age=5},
                new People(){Id=6,Name="345",Age=6},
            };
            List<People> peopleList = people.Where(func.Compile()).ToList();
        }
    }

    public class OperationsVisitor:ExpressionVisitor
    {
        public Expression Modify(Expression expression)
        {
            return base.Visit(expression);//调用父类的Visit方法
        }

        /// <summary>
        /// 二元表达式
        /// </summary>
        /// <param name="b"></param>
        /// <returns></returns>
        protected override Expression VisitBinary(BinaryExpression b)
        {
            if(b.NodeType==ExpressionType.Add)
            {
                Expression left = base.Visit(b.Left);
                Expression right = base.Visit(b.Right);
                return Expression.Subtract(left, right);
            }
            return base.VisitBinary(b);
        }

        protected override Expression VisitConstant(ConstantExpression c)
        {
            return base.VisitConstant(c);
        }

        protected override Expression VisitParameter(ParameterExpression p)
        {
            return base.VisitParameter(p);
        }

        protected override Expression VisitMethodCall(MethodCallExpression m)
        {
            return base.VisitMethodCall(m);
        }
    }

    public class People
    {
        public int Id;
        public int Age { get; set; }
        public string Name { get; set; }
    }

    public class ConditionBuilderVisitor:ExpressionVisitor
    {
        /// <summary>
        /// 栈:先进后出
        /// </summary>
        private Stack<string> _StringStack = new Stack<string>();

        public string Condition()
        {
            string condition = string.Concat(this._StringStack.ToArray());
            this._StringStack.Clear();
            return condition;
        }

        protected override Expression VisitBinary(BinaryExpression node)
        {
            this._StringStack.Push(")");
            base.Visit(node.Right);
            this._StringStack.Push(" " + node.NodeType.ToSqlOperator() + " ");
            base.Visit(node.Left);
            this._StringStack.Push("(");
            return node;
        }

        protected override Expression VisitConstant(ConstantExpression node)
        {
            if (node == null) throw new AggregateException("ConstantExpression");
            this._StringStack.Push("'" + node.Value + "'");
            return node;
        }

        protected override Expression VisitMember(MemberExpression node)
        {
            if (node == null) throw new ArgumentNullException("MemberExpression");
            this._StringStack.Push("[" + node.Member.Name + "]");
            return node;
        }      
        
        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            if (node == null) throw new ArgumentNullException("MethodCallExpression");
            string format;
            switch(node.Method.Name)
            {
                case "StartsWith":
                    format = "({0} LIKE {1}+'%')";
                    break;
                case "Contains":
                    format = "({0} LIKE '%'+{1}+'%')";
                    break;
                case "EndsWith":
                    format = "({0} LIKE '%'+{1})";
                    break;
                default:
                    throw new Exception("不支持该方法");
            }
            this.Visit(node.Object);
            this.Visit(node.Arguments);
            string right = this._StringStack.Pop();
            string left = this._StringStack.Pop();
            this._StringStack.Push(String.Format(format, left, right));
            return node;
        }
    }
    internal static class SqlOperator
    {
        internal static string ToSqlOperator(this ExpressionType type)
        {
            switch (type)
            {
                case (ExpressionType.AndAlso):
                case (ExpressionType.And):
                    return "AND";
                case (ExpressionType.OrElse):
                case (ExpressionType.Or):
                    return "OR";
                case (ExpressionType.Not):
                    return "NOT";
                case (ExpressionType.NotEqual):
                    return "<>";
                case (ExpressionType.GreaterThan):
                    return ">";
                case (ExpressionType.GreaterThanOrEqual):
                    return ">=";
                case (ExpressionType.LessThan):
                    return "<";
                case (ExpressionType.LessThanOrEqual):
                    return "<=";
                case (ExpressionType.Equal):
                    return "=";
                default:
                    throw new Exception("不支持该方法");
            }
        }
    }

    public static class ExpressionExtend
    {

        public static Expression<Func<T,bool>> And<T>(this Expression<Func<T,bool>> expr1,Expression<Func<T,bool>> expr2)
        {
            if (expr1 == null)
                return expr2;
            else if (expr2 == null)
                return expr1;

            ParameterExpression newParameter = Expression.Parameter(typeof(T), "c");
            NewExpressionVisitor visitor = new NewExpressionVisitor(newParameter);
            var left = visitor.Replace(expr1.Body);
            var right = visitor.Replace(expr2.Body);
            var body = Expression.And(left, right);
            return Expression.Lambda<Func<T, bool>>(body, newParameter);
        }

        public static Expression<Func<T,bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
        {
            if (expr1 == null)
                return expr2;
            else if (expr2 == null)
                return expr1;
            ParameterExpression newParameter = Expression.Parameter(typeof(T), "c");
            NewExpressionVisitor visitor = new NewExpressionVisitor(newParameter);
            var left = visitor.Replace(expr1.Body);
            var right = visitor.Replace(expr2.Body);
            var body = Expression.Or(left, right);
            return Expression.Lambda<Func<T, bool>>(body, newParameter);
        }

        public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> expr)
        {
            if (expr == null)
                return null;
            var candidateExpr = expr.Parameters[0];
            var body = Expression.Not(expr.Body);
            return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
        }
    }

    internal class NewExpressionVisitor:ExpressionVisitor
    {
        public ParameterExpression _NewParameter { get; private set; }  

        public NewExpressionVisitor(ParameterExpression parameter)
        {
            this._NewParameter = parameter;
        }

        public Expression Replace(Expression expression)
        {
            return this.Visit(expression);
        }

        protected override Expression VisitParameter(ParameterExpression node)
        {
            return this._NewParameter;
        }
    }

}

上一篇:2021牛客暑期多校训练营4 部分题题解


下一篇:JavaScript:关于事件处理程序何时可以直接访问元素的属性