临城网站建设,wordpress图片关联文章,有专门教做儿童美食的网站吗,建设银行网上银行登录入口一. 基本介绍 回忆#xff1a; 最早接触到表达式目录树(Expression)可能要追溯到几年前使用EF早期的时候#xff0c;发现where方法里的参数是ExpressionFuncT,bool这么一个类型#xff0c;当初不是很理解#xff0c;只是知道传入lambda表达式使用即可…一. 基本介绍 回忆 最早接触到表达式目录树(Expression)可能要追溯到几年前使用EF早期的时候发现where方法里的参数是ExpressionFuncT,bool这么一个类型当初不是很理解只是知道传入lambda表达式使用即可对于Expression和里面的FuncT,bool到底是怎么一种关系都不清楚。 今天带着回忆开发初期的心情详细的介绍一下这一段时间对Expression的理解。 1. Expression与Func委托的区别 ①委托是一种类型是方法的抽象通过委托可以将方法以参数的形式传递给另一个方法同时调用委托的时候它缩包含的方法都会被实现。委托的关键字是delegate可以自定义委托也可以使用内置委托通过简化可以将Lambda表达式或Lambda语句赋值给委托委托的调用包括同步调用和异步调用。 ②表达式目录树(Expression),是一种数据结构可以利用Lambda表达式进行声明Lambda表达式的规则要符合Expression中Func委托的参数规则。
可以利用Lambda表达式进行声明但Lambda语句是不能声明的。 Expression调用Compile方法可以转换成TDelegate中的委托。
回顾委托的代码 1 {2 //1. Func委托,必须要有返回值最后一个参数为返回值,前面为输入参数3 Funcint, int, int func1 new Funcint, int, int((int m, int n) 4 {5 return m * n 2;6 });7 //对其进行最简化(Lambda语句)8 Funcint, int, int func2 (m, n) 9 {
10 return m * n 2;
11 };
12 //对其进行最简化(Lambda表达式)
13 Funcint, int, int func3 (m, n) m * n 2;
14 //调用委托
15 int result1 func1.Invoke(2, 3);
16 int result2 func2.Invoke(2, 3);
17 int result3 func3.Invoke(2, 3);
18 Console.WriteLine(委托三种形式结果分别为{0},{1},{2}, result1, result2, result3);
19 } 初识Expression表达式目录树的代码 1 {2 //报错 Lambda语句无法转换成表达式目录树3 //ExpressionFuncint, int, int exp1 (m, n) 4 //{5 // return m * n 2;6 //};7 8 //利用Lambda表达式 来声明 表达式目录树9 ExpressionFuncint, int, int exp2 (m, n) m * n 2;
10
11 //利用Compile编译可以将表达式目录树转换成委托
12 Funcint, int, int func exp2.Compile();
13 int result1 func.Invoke(2, 3);
14 Console.WriteLine(表达式目录树转换成委托后结果为{0}, result1);
15 } 执行结果 2. 自己拼接表达式目录树 ①. 核心先把Lambda表达式写出来然后用ILSpy工具进行编译就能把表达式目录树的拼接过程给显示出来当然有些代码不是我们想要的需要转换成C#代码。 ②. 了解拼接要用到的类型和方法: 类型常量值表达式(ConstantExpression)、命名参数表达式(ParameterExpression)、含二元运算符的表达式(BinaryExpression) 方法设置常量表达式的值(Constant方法)、设置参数表达式的变量(Parameter方法)、相加(Add方法)、相乘(Multiply方法)、Lambda方法将拼接的二元表达式转换成表达式目录树 ③. 步骤声明变量和常量→进行二元计算→将最终二元运算符的表达式转换成表达式目录树 下面分享拼接 ExpressionFuncint, int, int express1 (m, n) m * n 2; 的代码 {Funcint, int, int func1 (m, n) m * n 2;//利用反编译工具翻译下面这个ExpressionExpressionFuncint, int, int express1 (m, n) m * n 2;//下面是反编译以后的代码(自己稍加改进了一下)ParameterExpression parameterExpression Expression.Parameter(typeof(int), m);ParameterExpression parameterExpression2 Expression.Parameter(typeof(int), n);BinaryExpression binaryExpression Expression.Multiply(parameterExpression, parameterExpression2);ConstantExpression constantExpression Expression.Constant(2, typeof(int));BinaryExpression binaryFinalBody Expression.Add(binaryExpression, constantExpression);ExpressionFuncint, int, int express Expression.LambdaFuncint, int, int(binaryFinalBody, new ParameterExpression[]{parameterExpression, parameterExpression2});int result express.Compile().Invoke(2, 3);Console.WriteLine(自己拼接的表达式目录树的结果为{0}, result);} 运行结果 二. 实体间Copy赋值的几类处理方案 背景 在实际开发中我们可能经常会遇到这种场景两个实体的名称不同属性完全相同需要将一个实体的值赋值给另一个对应实体上的属性。 解决这类问题通常有以下几种方案 1. 直接硬编码的形式速度最快(0.126s) 2. 通过反射遍历属性的形式 (6.328s) 3. 利用序列化和反序列化的形式将复制实体序列化字符串在把该字符串反序列化被赋值实体(7.768s) 4. 字典缓存表达式目录树(Lambda的拼接代码了解即可) 0.663s 5. 泛型缓存表达式目录树(Lambda的拼接代码了解即可) (2.134s) 代码分享 1 public static class CopyUtils2 {3 //字典缓存4 private static Dictionarystring, object _Dic new Dictionarystring, object();5 6 public static void Show()7 {8 //0. 准备实体 9 User user new User()10 {11 id 1,12 userName ypf,13 userAge 314 };15 long time1 0;16 long time2 0;17 long time3 0;18 long time4 0;19 long time5 0;20 21 #region 1-直接硬编码的形式22 {23 Task.Run(() 24 {25 Stopwatch watch new Stopwatch();26 watch.Start();27 for (int i 0; i 1000000; i)28 {29 UserCopy userCopy new UserCopy()30 {31 id user.id,32 userName user.userName,33 userAge user.userAge,34 };35 }36 watch.Stop();37 time1 watch.ElapsedMilliseconds;38 Console.WriteLine(方案1所需要的时间为:{0}, time1);39 });40 41 }42 #endregion43 44 #region 2-反射遍历属性45 {46 Task.Run(() 47 {48 Stopwatch watch new Stopwatch();49 watch.Start();50 for (int i 0; i 1000000; i)51 {52 CopyUtils.ReflectionMapperUser, UserCopy(user);53 }54 watch.Stop();55 time2 watch.ElapsedMilliseconds;56 Console.WriteLine(方案2所需要的时间为:{0}, time2);57 });58 }59 #endregion60 61 #region 3-序列化和反序列化62 {63 Task.Run(() 64 {65 Stopwatch watch new Stopwatch();66 watch.Start();67 for (int i 0; i 1000000; i)68 {69 CopyUtils.SerialzerMapperUser, UserCopy(user);70 }71 watch.Stop();72 time3 watch.ElapsedMilliseconds;73 Console.WriteLine(方案3所需要的时间为:{0}, time3);74 });75 76 }77 #endregion78 79 #region 04-字典缓存表达式目录树80 {81 Task.Run(() 82 {83 Stopwatch watch new Stopwatch();84 watch.Start();85 for (int i 0; i 1000000; i)86 {87 CopyUtils.DicExpressionMapperUser, UserCopy(user);88 }89 watch.Stop();90 time4 watch.ElapsedMilliseconds;91 Console.WriteLine(方案4所需要的时间为:{0}, time4);92 });93 }94 #endregion95 96 #region 05-泛型缓存表达式目录树97 {98 Task.Run(() 99 {
100 Stopwatch watch new Stopwatch();
101 watch.Start();
102 for (int i 0; i 1000000; i)
103 {
104 GenericExpressionMapperUser, UserCopy.Trans(user);
105 }
106 watch.Stop();
107 time5 watch.ElapsedMilliseconds;
108 Console.WriteLine(方案5所需要的时间为:{0}, time5);
109 });
110 }
111 #endregion
112
113 } 上述代码涉及到的几个封装 View Code 泛型缓存
最终运行结果 三. 剥离表达式目录树 这里补充几个常用的表达式目录树的拼接代码And、Or、Not 。 ExpressionExtend扩展类代码 1 public static class ExpressionExtend2 {3 /// summary4 /// 合并表达式 expr1 AND expr25 /// /summary6 /// typeparam nameT/typeparam7 /// param nameexpr1/param8 /// param nameexpr2/param9 /// returns/returns
10 public static ExpressionFuncT, bool AndT(this ExpressionFuncT, bool expr1, ExpressionFuncT, bool expr2)
11 {
12 ParameterExpression newParameter Expression.Parameter(typeof(T), c);
13 NewExpressionVisitor visitor new NewExpressionVisitor(newParameter);
14
15 var left visitor.Replace(expr1.Body);
16 var right visitor.Replace(expr2.Body);
17 var body Expression.And(left, right);
18 return Expression.LambdaFuncT, bool(body, newParameter);
19
20 }
21 /// summary
22 /// 合并表达式 expr1 or expr2
23 /// /summary
24 /// typeparam nameT/typeparam
25 /// param nameexpr1/param
26 /// param nameexpr2/param
27 /// returns/returns
28 public static ExpressionFuncT, bool OrT(this ExpressionFuncT, bool expr1, ExpressionFuncT, bool expr2)
29 {
30
31 ParameterExpression newParameter Expression.Parameter(typeof(T), c);
32 NewExpressionVisitor visitor new NewExpressionVisitor(newParameter);
33
34 var left visitor.Replace(expr1.Body);
35 var right visitor.Replace(expr2.Body);
36 var body Expression.Or(left, right);
37 return Expression.LambdaFuncT, bool(body, newParameter);
38 }
39 public static ExpressionFuncT, bool NotT(this ExpressionFuncT, bool expr)
40 {
41 var candidateExpr expr.Parameters[0];
42 var body Expression.Not(expr.Body);
43
44 return Expression.LambdaFuncT, bool(body, candidateExpr);
45 }
46 } NewExpressionVisitor建立新表达式辅助类代码 1 /// summary2 /// 建立新表达式3 /// /summary4 internal class NewExpressionVisitor : ExpressionVisitor5 {6 public ParameterExpression _NewParameter { get; private set; }7 public NewExpressionVisitor(ParameterExpression param)8 {9 this._NewParameter param;
10 }
11 public Expression Replace(Expression exp)
12 {
13 return this.Visit(exp);
14 }
15 protected override Expression VisitParameter(ParameterExpression node)
16 {
17 return this._NewParameter;
18 }
19 } 如何使用的代码 1 public class VisitorUtils2 {3 public static void Show()4 {5 ExpressionFuncUser, bool lambda1 x x.userAge 5;6 ExpressionFuncUser, bool lambda2 x x.id 5;7 ExpressionFuncUser, bool lambda3 lambda1.And(lambda2);8 ExpressionFuncUser, bool lambda4 lambda1.Or(lambda2);9 ExpressionFuncUser, bool lambda5 lambda1.Not();
10
11 Do1(lambda1);
12 Do1(lambda2);
13 Do1(lambda3);
14 Do1(lambda4);
15 Do1(lambda5);
16 }
17
18 private static void Do1(ExpressionFuncUser, bool func)
19 {
20 ListUser user new ListUser()
21 {
22 new User(){id4,userName123,userAge4},
23 new User(){id5,userName234,userAge5},
24 new User(){id6,userName345,userAge6},
25 };
26
27 ListUser peopleList user.Where(func.Compile()).ToList();
28 }
29 }