diff --git a/src/DotNetCommon.Core/DotNetCommon.Core.csproj b/src/DotNetCommon.Core/DotNetCommon.Core.csproj index 3989557772ae54e7df9c2fe89bf7fea0ecb149c7..e361914ebce92c80751ce10651171aceaeb9d113 100644 --- a/src/DotNetCommon.Core/DotNetCommon.Core.csproj +++ b/src/DotNetCommon.Core/DotNetCommon.Core.csproj @@ -1,7 +1,7 @@ - 4.1.1 + 4.2.0 True .net常用功能及数据模型,包含: diff --git a/src/DotNetCommon.Core/ExpressionHelper.cs b/src/DotNetCommon.Core/ExpressionHelper.cs index e3f9f9f5adf433ee70331603d84b392234b7735a..e1e5aab9166c2fce3f6f84036be9cb613658d646 100644 --- a/src/DotNetCommon.Core/ExpressionHelper.cs +++ b/src/DotNetCommon.Core/ExpressionHelper.cs @@ -165,6 +165,7 @@ namespace DotNetCommon /// /// /// + /// 是否保留此表达式,比如: 在 根据lambda解析生成update语句的时候,期望保留 new Person{} /// /// 简化的原理:
/// @@ -175,7 +176,7 @@ namespace DotNetCommon /// ///
/// - public static Expression ReduceLambda(LambdaExpression lambdaExpression) + public static Expression ReduceLambda(LambdaExpression lambdaExpression, Func isKeepCallBack = null) { var root = new ExpressionNode { @@ -198,7 +199,7 @@ namespace DotNetCommon { if (node.Expression == null) return; var visit = GetVisit(node.NodeType); - visit.Reduce(node, VisitTree); + visit.Reduce(node, VisitTree, isKeepCallBack); } } private static Dictionary _caches = new Dictionary() diff --git a/src/DotNetCommon.Core/Expressions/Base/BaseVisit.cs b/src/DotNetCommon.Core/Expressions/Base/BaseVisit.cs index d6c513138246fe108d162ca40e1215edc9f40a21..881b03efa4c1d8031410430f469c24d3b211d547 100644 --- a/src/DotNetCommon.Core/Expressions/Base/BaseVisit.cs +++ b/src/DotNetCommon.Core/Expressions/Base/BaseVisit.cs @@ -34,12 +34,15 @@ namespace DotNetCommon.Expressions.Base /// /// /// - public void Reduce(ExpressionNode node, Action visit) + /// 是否保留此表达式,比如: 在 根据lambda解析生成update语句的时候,期望保留 new Person{} + public void Reduce(ExpressionNode node, Action visit, Func isKeepCallBack) { Prepare(node); node.Children.ForEach(x => visit(x)); node.FullMarkString = GenerateFullMarkString(node); - SimpleReduce(node); + var isKeep = false; + if (isKeepCallBack != null) isKeep = isKeepCallBack(node.Expression); + SimpleReduce(node, isKeep); Reduce2(node); } /// @@ -57,48 +60,58 @@ namespace DotNetCommon.Expressions.Base /// 这样, 不含参数的子节点将被简化, 如果所有子节点都不含参数, 那说明简化的时机还没到, 延迟到父节点进行判断 /// /// - private void SimpleReduce(ExpressionNode node) + /// + private void SimpleReduce(ExpressionNode node, bool isKeep) { - //判断是否能简化 - if (node.Children.Count > 1) + var canReduce = false; + if (isKeep) { - var canReduce = false; - for (int i = 0; i < node.Children.Count - 1; i++) + canReduce = true; + //hack 将自身标记为 parameter 防止被上级简化 + node.IsParameter = true; + } + else + { + if (node.Children.Count > 1) { - if (node.Children[i].HasParameter ^ node.Children[i + 1].HasParameter) + for (int i = 0; i < node.Children.Count - 1; i++) { - //不相同 要进行简化 - canReduce = true; - break; + if (node.Children[i].HasParameter ^ node.Children[i + 1].HasParameter) + { + //不相同 要进行简化 + canReduce = true; + break; + } } + } - if (canReduce) + } + if (canReduce) + { + for (int i = 0; i < node.Children.Count; i++) { - for (int i = 0; i < node.Children.Count; i++) + var child = node.Children[i]; + if (!child.HasParameter && child.Expression != null) { - var child = node.Children[i]; - if (!child.HasParameter && child.Expression != null) + if (child.NodeType == ExpressionType.Lambda) { - if (child.NodeType == ExpressionType.Lambda) - { - //lambda表达式节点不能再进一步简化,最多将它的body简化成常量 - //因为有的方法本身接受的就是lambda表达式 - node.Children[i]._updateRequest = true; - //node.Children[i].FullMarkString = GenerateFullMarkString(node.Children[i]); - } - else if (child.NodeType != ExpressionType.Constant) + //lambda表达式节点不能再进一步简化,最多将它的body简化成常量 + //因为有的方法本身接受的就是lambda表达式 + node.Children[i]._updateRequest = true; + //node.Children[i].FullMarkString = GenerateFullMarkString(node.Children[i]); + } + else if (child.NodeType != ExpressionType.Constant) + { + //进行简化 + var res = child.Reduce(); + var contant = Expression.Constant(res, child.Expression.Type); + node.Children[i] = new ExpressionNode { - //进行简化 - var res = child.Reduce(); - var contant = Expression.Constant(res, child.Expression.Type); - node.Children[i] = new ExpressionNode - { - Parent = node, - Expression = contant, - _updateRequest = true, - }; - node.Children[i].FullMarkString = ConstantVisit.StaticGenerateFullMarkString(node.Children[i]); - } + Parent = node, + Expression = contant, + _updateRequest = true, + }; + node.Children[i].FullMarkString = ConstantVisit.StaticGenerateFullMarkString(node.Children[i]); } } } diff --git a/src/DotNetCommon.Core/Expressions/Visit/VisitImplements.cs b/src/DotNetCommon.Core/Expressions/Visit/VisitImplements.cs index 6bddd5fb799b1a7536b86099a9dbfbcf7c4242b8..e88302db1df13d9e424b2fb3702116ef0ad8fbbc 100644 --- a/src/DotNetCommon.Core/Expressions/Visit/VisitImplements.cs +++ b/src/DotNetCommon.Core/Expressions/Visit/VisitImplements.cs @@ -637,9 +637,9 @@ namespace DotNetCommon.Expressions.Visit //先更新New newExpression = newExpression.Update(node.Children.Take(memberSetIndex).Select(i => i.Expression)); //再更新ListInit - for (int i = 1; i < node.Children.Count; i++) + for (int i = memberSetIndex; i < node.Children.Count; i++) { - inits.Add(listInitExpression.Initializers[i - 1].Update(new[] { node.Children[i].Expression })); + inits.Add(listInitExpression.Initializers[i - memberSetIndex].Update(new[] { node.Children[i].Expression })); } return listInitExpression.Update(newExpression, inits); } diff --git a/tests/DotNetCommon.Test/ExpressionHelperTests/ReduceLambdaTests.cs b/tests/DotNetCommon.Test/ExpressionHelperTests/ReduceLambdaTests.cs index 99e208a3d529a0de2e0684f2b6e6785a9ebe288d..90cfc7b149bb8923b6fc314122c104e0b5a41eac 100644 --- a/tests/DotNetCommon.Test/ExpressionHelperTests/ReduceLambdaTests.cs +++ b/tests/DotNetCommon.Test/ExpressionHelperTests/ReduceLambdaTests.cs @@ -427,6 +427,48 @@ namespace DotNetCommon.Test.ExpressionHelperTests res.FirstOrDefault().Age.ShouldBe(18); } #endregion + + #region canReduce + class Person8 + { + public int Id { get; set; } + public string Name { get; set; } + public List Children { get; set; } + } + + + [Test] + public void IsKeepTest() + { + var names = new List() { "tom", "lisa" }; + Expression> lambda = p => new Person8 + { + Id = p.Id + 1, + Name = names.FirstOrDefault(), + Children = new List + { + new Person8() { Id = names.Count}, + p + } + }; + var res = ExpressionHelper.ReduceLambda(lambda, exp => exp.NodeType == ExpressionType.MemberInit); + res.ToString().Replace("\r\n", "").ShouldBe(@"p => new Person8() {Id = (p.Id + 1), Name = ""tom"", Children = new List`1() {Void Add(Person8)(new Person8() {Id = 2}), Void Add(Person8)(p)}}".Replace("\r\n", "")); + + lambda = p => new Person8 + { + Id = p.Id + 1, + Name = names.FirstOrDefault(), + Children = new List + { + new Person8() { Id = names.Count}, + new Person8() { Id = names.Count}, + } + }; + res = ExpressionHelper.ReduceLambda(lambda, exp => exp.NodeType == ExpressionType.ListInit); + res.ToString().Replace("\r\n", "").ShouldBe(@"p => new Person8() {Id = (p.Id + 1), Name = ""tom"", Children = new List`1() {Void Add(Person8)(value(DotNetCommon.Test.ExpressionHelperTests.EveryNodeTypeTests+Person8)), Void Add(Person8)(value(DotNetCommon.Test.ExpressionHelperTests.EveryNodeTypeTests+Person8))}}".Replace("\r\n", "")); + } + + #endregion } #endregion