ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

表达式目录树学习笔记

2021-01-30 22:58:39  阅读:133  来源: 互联网

标签:return 笔记 public typeof var new Expression 目录 表达式


表达式目录树学习笔记

第一堂课:

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;
        }
    }

}

标签:return,笔记,public,typeof,var,new,Expression,目录,表达式
来源: https://blog.csdn.net/qq_20792765/article/details/113448033

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有