added foreach with index linq.
This commit is contained in:
		
							parent
							
								
									48db853236
								
							
						
					
					
						commit
						f0ed7d9bd5
					
				
							
								
								
									
										231
									
								
								PoweredSoft.DynamicLinq.ConsoleApp/BetterParserProto1.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										231
									
								
								PoweredSoft.DynamicLinq.ConsoleApp/BetterParserProto1.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,231 @@ | ||||
| using PoweredSoft.DynamicLinq.Dal.Pocos; | ||||
| using PoweredSoft.DynamicLinq.Helpers; | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Linq.Expressions; | ||||
| using System.Text; | ||||
| using System.Threading.Tasks; | ||||
| 
 | ||||
| #if false | ||||
| 
 | ||||
| namespace PoweredSoft.DynamicLinq.ConsoleApp | ||||
| { | ||||
|     public class StaticProto1 | ||||
|     { | ||||
|         public static void Run() | ||||
|         { | ||||
|             var q = new List<Author>().AsQueryable(); | ||||
|             q.Select(t => new | ||||
|             { | ||||
|                 Ids = t.Posts.SelectMany(t2 => t2.Comments.Select(t3 => t3.CommentLikes)) | ||||
|             }); | ||||
| 
 | ||||
|             var expressionParser = new ExpressionParser(typeof(Author), "Posts.Comments.CommentLikes"); | ||||
|             expressionParser.Parse(); | ||||
| 
 | ||||
|             var finalExpression = CreateSelectExpressionFromParsed(expressionParser, SelectCollectionHandling.Flatten, SelectNullHandling.New); | ||||
|         } | ||||
| 
 | ||||
|         public static Expression CreateSelectExpressionFromParsed(ExpressionParser expressionParser, | ||||
|            SelectCollectionHandling selectCollectionHandling = SelectCollectionHandling.LeaveAsIs, | ||||
|            SelectNullHandling nullChecking = SelectNullHandling.LeaveAsIs) | ||||
|         { | ||||
|             Type nullHandlingRightType = null; | ||||
|             Expression nullHandlingNullValue = null; | ||||
| 
 | ||||
|             if (nullChecking != SelectNullHandling.LeaveAsIs) | ||||
|             { | ||||
|                 var withoutNullCheckResult = CreateSelectExpressionFromParsed(expressionParser, SelectCollectionHandling.Flatten, SelectNullHandling.LeaveAsIs); | ||||
|                 if (QueryableHelpers.IsGenericEnumerable(withoutNullCheckResult.Type)) | ||||
|                     nullHandlingRightType = typeof(List<>).MakeGenericType(withoutNullCheckResult.Type.GenericTypeArguments.First()); | ||||
|                 else | ||||
|                     nullHandlingRightType = withoutNullCheckResult.Type; | ||||
| 
 | ||||
|                 nullHandlingNullValue = nullChecking == SelectNullHandling.Default | ||||
|                     ? Expression.Default(nullHandlingRightType) as Expression | ||||
|                     : Expression.New(nullHandlingRightType) as Expression; | ||||
|             } | ||||
| 
 | ||||
|             // reversed :) | ||||
|             var reversedCopy = expressionParser.Groups.Select(t => t).ToList(); | ||||
|             reversedCopy.Reverse(); | ||||
| 
 | ||||
|             MethodCallExpression lastSelectExpression = null; | ||||
|             Expression ret = null; | ||||
| 
 | ||||
|             foreach (var t in reversedCopy) | ||||
|             { | ||||
|                 if (true == t.Parent?.LastPiece().IsGenericEnumerable()) | ||||
|                 { | ||||
|                     if (lastSelectExpression == null) | ||||
|                         lastSelectExpression = RegroupSelectExpressions(t, selectCollectionHandling); | ||||
|                     else | ||||
|                         lastSelectExpression = RegroupSelectExpressions(t, lastSelectExpression, selectCollectionHandling); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             ret = lastSelectExpression; | ||||
|             return ret; | ||||
|         } | ||||
| 
 | ||||
|         public static MethodCallExpression RegroupSelectExpressions(ExpressionParameterGroup group, SelectCollectionHandling selectCollectionHandling) | ||||
|         { | ||||
|             MethodCallExpression ret = null; | ||||
|             var lambda = group.CreateLambda(); | ||||
|             var parentExpression = group.Parent.LastExpression(); | ||||
|             var isParentExpressionGenericEnumerable = QueryableHelpers.IsGenericEnumerable(parentExpression); | ||||
|             var parentExpressionGenericEnumerableType = isParentExpressionGenericEnumerable ? parentExpression.Type.GenericTypeArguments.First() : null; | ||||
|             var lastPiece = group.LastPiece(); | ||||
| 
 | ||||
|             if (selectCollectionHandling == SelectCollectionHandling.LeaveAsIs || !lastPiece.IsGenericEnumerable()) | ||||
|                 ret = Expression.Call(typeof(Enumerable), "Select", new Type[] { parentExpressionGenericEnumerableType, lastPiece.Expression.Type }, parentExpression, lambda); | ||||
|             else | ||||
|                 ret = Expression.Call(typeof(Enumerable), "SelectMany", new Type[] { parentExpressionGenericEnumerableType, lastPiece.GetGenericEnumerableType() }, parentExpression, lambda); | ||||
| 
 | ||||
|             return ret; | ||||
|         } | ||||
| 
 | ||||
|         public static MethodCallExpression RegroupSelectExpressions(ExpressionParameterGroup group, MethodCallExpression innerSelect, SelectCollectionHandling selectCollectionHandling) | ||||
|         { | ||||
|             var parent = group.Parent; | ||||
|             var parentLastPiece = parent.LastPiece(); | ||||
| 
 | ||||
|             MethodCallExpression ret = null; | ||||
|             var lambda = Expression.Lambda(innerSelect, group.Parameter); | ||||
|             if (selectCollectionHandling == SelectCollectionHandling.LeaveAsIs) | ||||
|                 ret = Expression.Call(typeof(Enumerable), "Select", new Type[] { parentLastPiece.GetGenericEnumerableType(), innerSelect.Type }, parentLastPiece.Expression, lambda); | ||||
|             else | ||||
|                 ret = Expression.Call(typeof(Enumerable), "SelectMany", new Type[] { parentLastPiece.GetGenericEnumerableType(), innerSelect.Type.GenericTypeArguments.First() }, parentLastPiece.Expression, lambda); | ||||
| 
 | ||||
|             return ret; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     public class ExpressionParameterGroup | ||||
|     { | ||||
|         public ExpressionParameterGroup Parent { get; set; } | ||||
|         public ParameterExpression Parameter { get; set; } | ||||
|         public List<ExpressionPiece> Pieces { get; set; } = new List<ExpressionPiece>(); | ||||
| 
 | ||||
|         public ExpressionParameterGroup(ParameterExpression parameter) | ||||
|         { | ||||
|             Parameter = parameter; | ||||
|         } | ||||
| 
 | ||||
|         public void AddSubPart(ExpressionPiece expressionPart) | ||||
|         { | ||||
|             Pieces.Add(expressionPart); | ||||
|         } | ||||
| 
 | ||||
|         public Expression LastExpression() => LastPiece().Expression; | ||||
| 
 | ||||
|         public ExpressionPiece LastPiece() => Pieces.Last(); | ||||
| 
 | ||||
|         public LambdaExpression CreateLambda() | ||||
|         { | ||||
|             var lastExpression = LastPiece().Expression; | ||||
|             var lambda = Expression.Lambda(lastExpression, Parameter); | ||||
|             return lambda; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public class ExpressionPiece | ||||
|     { | ||||
|         public ExpressionParameterGroup Parameter { get; set; } | ||||
|         public ExpressionPiece Parent { get; set; } | ||||
|         public Expression Expression { get; set; } | ||||
| 
 | ||||
|         public ExpressionPiece(ExpressionParameterGroup parameter, ExpressionPiece parent = null) | ||||
|         { | ||||
|             Parameter = parameter; | ||||
|             Parent = parent; | ||||
|         } | ||||
| 
 | ||||
|         public void Resolve(string piece) | ||||
|         { | ||||
|             Expression = Expression.PropertyOrField(Parent?.Expression ?? Parameter.Parameter, piece); | ||||
|         } | ||||
| 
 | ||||
|         public bool IsGenericEnumerable() => QueryableHelpers.IsGenericEnumerable(Expression); | ||||
|         public Type GetGenericEnumerableType() => Expression.Type.GenericTypeArguments.First(); | ||||
|     } | ||||
| 
 | ||||
|     public class ExpressionParser | ||||
|     { | ||||
|         public ParameterExpression Parameter { get; protected set; } | ||||
|         public string Path { get; protected set; } | ||||
|         public List<ExpressionParameterGroup> Groups { get; set; } = new List<ExpressionParameterGroup>(); | ||||
| 
 | ||||
|         public ExpressionParser(Type type, string path) : this(Expression.Parameter(type), path) | ||||
|         { | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         public ExpressionParser(ParameterExpression parameter, string path) | ||||
|         { | ||||
|             if (parameter == null) | ||||
|                 throw new ArgumentNullException("parameter"); | ||||
| 
 | ||||
|             if (string.IsNullOrEmpty(path)) | ||||
|                 throw new ArgumentNullException("path"); | ||||
| 
 | ||||
|             Parameter = parameter; | ||||
|             Path = path; | ||||
|         } | ||||
| 
 | ||||
|         public void Parse() | ||||
|         { | ||||
|             Groups = new List<ExpressionParameterGroup>(); | ||||
|             var pieces = Path.Split('.').ToList(); | ||||
| 
 | ||||
|             // create the current parameter. | ||||
|             var currentGroup = CreateAndAddParameterGroup(Parameter); | ||||
|             ExpressionPiece parentPiece = null; | ||||
| 
 | ||||
|             int indexOfPiece = -1; | ||||
|             pieces.ForEach(piece => | ||||
|             { | ||||
|                 ++indexOfPiece; | ||||
|                 bool isLast = indexOfPiece == pieces.Count - 1; | ||||
| 
 | ||||
|                 var expressionPiece = new ExpressionPiece(currentGroup, parentPiece); | ||||
|                 expressionPiece.Resolve(piece); | ||||
|                 currentGroup.AddSubPart(expressionPiece); | ||||
| 
 | ||||
|                 // rest is only if its not the last piece. | ||||
|                 if (isLast) return; | ||||
| 
 | ||||
|                 if (expressionPiece.IsGenericEnumerable()) | ||||
|                 { | ||||
|                     var param = Expression.Parameter(expressionPiece.GetGenericEnumerableType()); | ||||
|                     currentGroup = CreateAndAddParameterGroup(param, currentGroup); | ||||
|                     parentPiece = null; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     parentPiece = expressionPiece; | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         public ExpressionParameterGroup CreateAndAddParameterGroup(ParameterExpression parameter, ExpressionParameterGroup parent = null) | ||||
|         { | ||||
|             var group = new ExpressionParameterGroup(parameter); | ||||
| 
 | ||||
|             if (parent != null) | ||||
|                 group.Parent = parent; | ||||
| 
 | ||||
|             Groups.Add(group); | ||||
|             return group; | ||||
|         } | ||||
| 
 | ||||
|         public ExpressionParameterGroup LastGroup() | ||||
|         { | ||||
|             return this.Groups.Last(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										92
									
								
								PoweredSoft.DynamicLinq.ConsoleApp/BetterProto2.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								PoweredSoft.DynamicLinq.ConsoleApp/BetterProto2.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,92 @@ | ||||
| using PoweredSoft.DynamicLinq.Dal.Pocos; | ||||
| using PoweredSoft.DynamicLinq.Helpers; | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Linq.Expressions; | ||||
| using System.Text; | ||||
| using System.Threading.Tasks; | ||||
| 
 | ||||
| namespace PoweredSoft.DynamicLinq.ConsoleApp | ||||
| { | ||||
|     public class BetterProto2 | ||||
|     { | ||||
|         /* | ||||
|          *  (parent, innerExpression, innerExpressionLambda) => | ||||
|                 { | ||||
|                     var listGenericArgumentType = parent.Type.GetGenericArguments().First(); | ||||
|                     Expression ret = null; | ||||
|                     if (selectCollectionHandling == SelectCollectionHandling.LeaveAsIs || !QueryableHelpers.IsGenericEnumerable(innerExpression)) | ||||
|                         ret = Expression.Call(typeof(Enumerable), "Select", new Type[] { listGenericArgumentType, innerExpression.Type }, parent, innerExpressionLambda); | ||||
|                     else | ||||
|                         ret = Expression.Call(typeof(Enumerable), "SelectMany", new Type[] { listGenericArgumentType, innerExpression.Type.GenericTypeArguments.First() }, parent, innerExpressionLambda); | ||||
| 
 | ||||
|                     return ret; | ||||
|                 } | ||||
|          */ | ||||
|         public static void Run() | ||||
|         { | ||||
|             var ep = new ExpressionParser(typeof(Author), "Posts.Comments.Id"); | ||||
|             ep.Parse(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public class ExpressionParserPiece | ||||
|     { | ||||
|         public ParameterExpression Parameter { get; set; } | ||||
|         public MemberExpression MemberExpression { get; set; } | ||||
|         public ExpressionParserPiece Parent { get; set; } | ||||
| 
 | ||||
|         public bool IsGenericEnumerable => QueryableHelpers.IsGenericEnumerable(MemberExpression); | ||||
|         public Type EnumerableType => MemberExpression.Type.GenericTypeArguments.FirstOrDefault(); | ||||
|     } | ||||
| 
 | ||||
|     public class ExpressionParser | ||||
|     { | ||||
|         public ParameterExpression Parameter { get; protected set; } | ||||
|         public string Path { get; set; } | ||||
|         public List<ExpressionParserPiece> Pieces { get; set; } = new List<ExpressionParserPiece>(); | ||||
| 
 | ||||
|         public ExpressionParser(Type type, string path) : this(Expression.Parameter(type), path) | ||||
|         { | ||||
|              | ||||
|         } | ||||
| 
 | ||||
|         public ExpressionParser(ParameterExpression parameter, string path) | ||||
|         { | ||||
|             Parameter = parameter; | ||||
|             Path = path; | ||||
|         } | ||||
| 
 | ||||
|         public void Parse() | ||||
|         { | ||||
|             Pieces.Clear(); | ||||
| 
 | ||||
|             var param = Parameter; | ||||
|             var pathPieces = Path.Split('.').ToList(); | ||||
|             ExpressionParserPiece parent = null; | ||||
| 
 | ||||
|             pathPieces.ForEach(pp => | ||||
|             { | ||||
|                 var memberExpression = Expression.PropertyOrField(param, pp); | ||||
|                 var current = new ExpressionParserPiece | ||||
|                 { | ||||
|                     Parameter = param, | ||||
|                     MemberExpression = memberExpression, | ||||
|                     Parent = parent | ||||
|                 }; | ||||
| 
 | ||||
|                 Pieces.Add(current); | ||||
|                 param = ResolveNextParam(current); | ||||
|                 parent = current; | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         private ParameterExpression ResolveNextParam(ExpressionParserPiece current) | ||||
|         { | ||||
|             var type = current.IsGenericEnumerable ? current.EnumerableType : current.MemberExpression.Type; | ||||
|             var result = Expression.Parameter(type); | ||||
|             return result; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -42,6 +42,8 @@ | ||||
|     <Reference Include="System.Xml" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <Compile Include="BetterParserProto1.cs" /> | ||||
|     <Compile Include="BetterProto2.cs" /> | ||||
|     <Compile Include="Program.cs" /> | ||||
|     <Compile Include="Properties\AssemblyInfo.cs" /> | ||||
|   </ItemGroup> | ||||
|  | ||||
| @ -14,106 +14,8 @@ namespace PoweredSoft.DynamicLinq.ConsoleApp | ||||
|     { | ||||
|         static void Main(string[] args) | ||||
|         { | ||||
|             var q = new List<Author>().AsQueryable(); | ||||
|             q.Select(t => new | ||||
|             { | ||||
|                 Ids = t.Posts.SelectMany(t2 => t2.Comments.Select(t3 => t3.CommentLikes)) | ||||
|             }); | ||||
| 
 | ||||
|             var expressionParser = new ExpressionParser(typeof(Author), "Posts.Comments.CommentLikes"); | ||||
|             expressionParser.Parse(); | ||||
| 
 | ||||
|             var finalExpression = CreateSelectExpressionFromParsed(expressionParser, SelectCollectionHandling.Flatten, SelectNullHandling.New); | ||||
|             BetterProto2.Run(); | ||||
|         } | ||||
| 
 | ||||
|         public static Expression CreateSelectExpressionFromParsed(ExpressionParser expressionParser,  | ||||
|             SelectCollectionHandling selectCollectionHandling = SelectCollectionHandling.LeaveAsIs,  | ||||
|             SelectNullHandling nullChecking = SelectNullHandling.LeaveAsIs) | ||||
|         { | ||||
|             Type nullHandlingRightType = null; | ||||
|             Expression nullHandlingNullValue = null; | ||||
|              | ||||
|             if (nullChecking != SelectNullHandling.LeaveAsIs) | ||||
|             { | ||||
|                 var withoutNullCheckResult = CreateSelectExpressionFromParsed(expressionParser, SelectCollectionHandling.Flatten, SelectNullHandling.LeaveAsIs); | ||||
|                 if (QueryableHelpers.IsGenericEnumerable(withoutNullCheckResult.Type)) | ||||
|                     nullHandlingRightType = typeof(List<>).MakeGenericType(withoutNullCheckResult.Type.GenericTypeArguments.First()); | ||||
|                 else | ||||
|                     nullHandlingRightType = withoutNullCheckResult.Type; | ||||
| 
 | ||||
|                 nullHandlingNullValue = nullChecking == SelectNullHandling.Default | ||||
|                     ? Expression.Default(nullHandlingRightType) as Expression | ||||
|                     : Expression.New(nullHandlingRightType) as Expression; | ||||
|             } | ||||
| 
 | ||||
|             // reversed :) | ||||
|             var reversedCopy = expressionParser.Groups.Select(t => t).ToList(); | ||||
|             reversedCopy.Reverse(); | ||||
| 
 | ||||
|             MethodCallExpression lastSelectExpression = null; | ||||
|             Expression ret = null; | ||||
| 
 | ||||
|             foreach(var t in reversedCopy) | ||||
|             { | ||||
|                 if (true == t.Parent?.LastPiece().IsGenericEnumerable()) | ||||
|                 { | ||||
|                     if (lastSelectExpression == null) | ||||
|                         lastSelectExpression = RegroupSelectExpressions(t, selectCollectionHandling); | ||||
|                     else | ||||
|                         lastSelectExpression = RegroupSelectExpressions(t, lastSelectExpression, selectCollectionHandling); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             ret = lastSelectExpression; | ||||
|             return ret; | ||||
|         } | ||||
| 
 | ||||
|         public static MethodCallExpression RegroupSelectExpressions(ExpressionParameterGroup group, SelectCollectionHandling selectCollectionHandling) | ||||
|         { | ||||
|             MethodCallExpression ret = null; | ||||
|             var lambda = group.CreateLambda(); | ||||
|             var parentExpression = group.Parent.LastExpression(); | ||||
|             var isParentExpressionGenericEnumerable = QueryableHelpers.IsGenericEnumerable(parentExpression); | ||||
|             var parentExpressionGenericEnumerableType = isParentExpressionGenericEnumerable ? parentExpression.Type.GenericTypeArguments.First() : null; | ||||
|             var lastPiece = group.LastPiece(); | ||||
| 
 | ||||
|             if (selectCollectionHandling == SelectCollectionHandling.LeaveAsIs || !lastPiece.IsGenericEnumerable()) | ||||
|                 ret = Expression.Call(typeof(Enumerable), "Select", new Type[] { parentExpressionGenericEnumerableType, lastPiece.Expression.Type }, parentExpression, lambda); | ||||
|             else | ||||
|                 ret = Expression.Call(typeof(Enumerable), "SelectMany", new Type[] { parentExpressionGenericEnumerableType, lastPiece.GetGenericEnumerableType() }, parentExpression, lambda); | ||||
| 
 | ||||
|             return ret; | ||||
|         } | ||||
| 
 | ||||
|         public static MethodCallExpression RegroupSelectExpressions(ExpressionParameterGroup group, MethodCallExpression innerSelect, SelectCollectionHandling selectCollectionHandling) | ||||
|         { | ||||
|             var parent = group.Parent; | ||||
|             var parentLastPiece = parent.LastPiece(); | ||||
| 
 | ||||
|             MethodCallExpression ret = null; | ||||
|             var lambda = Expression.Lambda(innerSelect, group.Parameter); | ||||
|             if (selectCollectionHandling == SelectCollectionHandling.LeaveAsIs) | ||||
|                 ret = Expression.Call(typeof(Enumerable), "Select", new Type[] { parentLastPiece.GetGenericEnumerableType(), innerSelect.Type }, parentLastPiece.Expression, lambda); | ||||
|             else | ||||
|                 ret = Expression.Call(typeof(Enumerable), "SelectMany", new Type[] { parentLastPiece.GetGenericEnumerableType(), innerSelect.Type.GenericTypeArguments.First() }, parentLastPiece.Expression, lambda); | ||||
| 
 | ||||
|             return ret; | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         /* | ||||
|          *  (parent, innerExpression, innerExpressionLambda) => | ||||
|                 { | ||||
|                     var listGenericArgumentType = parent.Type.GetGenericArguments().First(); | ||||
|                     Expression ret = null; | ||||
|                     if (selectCollectionHandling == SelectCollectionHandling.LeaveAsIs || !QueryableHelpers.IsGenericEnumerable(innerExpression)) | ||||
|                         ret = Expression.Call(typeof(Enumerable), "Select", new Type[] { listGenericArgumentType, innerExpression.Type }, parent, innerExpressionLambda); | ||||
|                     else | ||||
|                         ret = Expression.Call(typeof(Enumerable), "SelectMany", new Type[] { listGenericArgumentType, innerExpression.Type.GenericTypeArguments.First() }, parent, innerExpressionLambda); | ||||
| 
 | ||||
|                     return ret; | ||||
|                 } | ||||
|          */ | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -5,130 +5,6 @@ using System.Linq.Expressions; | ||||
| 
 | ||||
| namespace PoweredSoft.DynamicLinq.Helpers | ||||
| { | ||||
|     public class ExpressionParameterGroup | ||||
|     { | ||||
|         public ExpressionParameterGroup Parent { get; set; } | ||||
|         public ParameterExpression Parameter { get; set; } | ||||
|         public List<ExpressionPiece> Pieces { get; set; } = new List<ExpressionPiece>(); | ||||
| 
 | ||||
|         public ExpressionParameterGroup(ParameterExpression parameter) | ||||
|         { | ||||
|             Parameter = parameter; | ||||
|         } | ||||
| 
 | ||||
|         public void AddSubPart(ExpressionPiece expressionPart) | ||||
|         { | ||||
|             Pieces.Add(expressionPart); | ||||
|         } | ||||
| 
 | ||||
|         public Expression LastExpression() => LastPiece().Expression; | ||||
| 
 | ||||
|         public ExpressionPiece LastPiece() => Pieces.Last(); | ||||
| 
 | ||||
|         public LambdaExpression CreateLambda() | ||||
|         { | ||||
|             var lastExpression = LastPiece().Expression; | ||||
|             var lambda = Expression.Lambda(lastExpression, Parameter); | ||||
|             return lambda; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public class ExpressionPiece | ||||
|     { | ||||
|         public ExpressionParameterGroup Parameter { get; set; } | ||||
|         public ExpressionPiece Parent { get; set; } | ||||
|         public Expression Expression { get; set; } | ||||
| 
 | ||||
|         public ExpressionPiece(ExpressionParameterGroup parameter, ExpressionPiece parent = null) | ||||
|         { | ||||
|             Parameter = parameter; | ||||
|             Parent = parent; | ||||
|         } | ||||
| 
 | ||||
|         public void Resolve(string piece) | ||||
|         { | ||||
|             Expression = Expression.PropertyOrField(Parent?.Expression ?? Parameter.Parameter, piece); | ||||
|         } | ||||
| 
 | ||||
|         public bool IsGenericEnumerable() => QueryableHelpers.IsGenericEnumerable(Expression); | ||||
|         public Type GetGenericEnumerableType() => Expression.Type.GenericTypeArguments.First(); | ||||
|     } | ||||
| 
 | ||||
|     public class ExpressionParser | ||||
|     { | ||||
|         public ParameterExpression Parameter { get; protected set; } | ||||
|         public string Path { get; protected set; } | ||||
|         public List<ExpressionParameterGroup> Groups { get; set; } = new List<ExpressionParameterGroup>(); | ||||
| 
 | ||||
|         public ExpressionParser(Type type, string path) : this(Expression.Parameter(type), path) | ||||
|         { | ||||
|              | ||||
|         } | ||||
| 
 | ||||
|         public ExpressionParser(ParameterExpression parameter, string path) | ||||
|         { | ||||
|             if (parameter == null) | ||||
|                 throw new ArgumentNullException("parameter"); | ||||
| 
 | ||||
|             if (string.IsNullOrEmpty(path)) | ||||
|                 throw new ArgumentNullException("path"); | ||||
| 
 | ||||
|             Parameter = parameter; | ||||
|             Path = path; | ||||
|         } | ||||
|          | ||||
|         public void Parse() | ||||
|         { | ||||
|             Groups = new List<ExpressionParameterGroup>(); | ||||
|             var pieces = Path.Split('.').ToList(); | ||||
| 
 | ||||
|             // create the current parameter. | ||||
|             var currentGroup = CreateAndAddParameterGroup(Parameter); | ||||
|             ExpressionPiece parentPiece = null; | ||||
| 
 | ||||
|             int indexOfPiece = -1; | ||||
|             pieces.ForEach(piece => | ||||
|             { | ||||
|                 ++indexOfPiece; | ||||
|                 bool isLast = indexOfPiece == pieces.Count - 1; | ||||
| 
 | ||||
|                 var expressionPiece = new ExpressionPiece(currentGroup, parentPiece); | ||||
|                 expressionPiece.Resolve(piece); | ||||
|                 currentGroup.AddSubPart(expressionPiece); | ||||
| 
 | ||||
|                 // rest is only if its not the last piece. | ||||
|                 if (isLast) return; | ||||
| 
 | ||||
|                 if (expressionPiece.IsGenericEnumerable()) | ||||
|                 { | ||||
|                     var param = Expression.Parameter(expressionPiece.GetGenericEnumerableType()); | ||||
|                     currentGroup = CreateAndAddParameterGroup(param, currentGroup); | ||||
|                     parentPiece = null; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     parentPiece = expressionPiece; | ||||
|                 } | ||||
|             });            | ||||
|         } | ||||
| 
 | ||||
|         public ExpressionParameterGroup CreateAndAddParameterGroup(ParameterExpression parameter, ExpressionParameterGroup parent = null) | ||||
|         { | ||||
|             var group = new ExpressionParameterGroup(parameter); | ||||
| 
 | ||||
|             if (parent != null) | ||||
|                 group.Parent = parent; | ||||
| 
 | ||||
|             Groups.Add(group); | ||||
|             return group; | ||||
|         } | ||||
| 
 | ||||
|         public ExpressionParameterGroup LastGroup() | ||||
|         { | ||||
|             return this.Groups.Last(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public class ExpressionPathPart | ||||
|     { | ||||
|         public Expression ParentExpression { get; set; } | ||||
|  | ||||
| @ -46,5 +46,33 @@ namespace PoweredSoft.DynamicLinq | ||||
| 
 | ||||
|         public static IQueryable GroupBy(this IEnumerable list, Type type, Action<GroupBuilder> callback) | ||||
|             => list.AsQueryable().GroupBy(type, callback); | ||||
| 
 | ||||
|         public static List<T> Reversed<T>(this List<T> list) | ||||
|         { | ||||
|             var copy = list.ToList(); | ||||
|             copy.Reverse(); | ||||
|             return copy; | ||||
|         } | ||||
| 
 | ||||
|         public delegate void ForEachDelegate<T>(T element, int index); | ||||
| 
 | ||||
|         public static void ForEach<T>(this List<T> list, ForEachDelegate<T> callback) | ||||
|         { | ||||
|             for (var i = 0; i < list.Count; i++) | ||||
|                 callback(list[i], i); | ||||
|         } | ||||
| 
 | ||||
|         public static void ReversedForEach<T>(this List<T> list, Action<T> action) | ||||
|         { | ||||
|             list.Reversed().ForEach(action); | ||||
|         } | ||||
| 
 | ||||
|         public static void ReversedForEach<T>(this List<T> list, ForEachDelegate<T> callback) | ||||
|         { | ||||
|             var reversed = list.Reversed(); | ||||
|             reversed.ForEach(callback); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|     } | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user