well advancing but not done yet :)

This commit is contained in:
David Lebée 2018-03-26 21:30:36 -05:00
parent dcd251f199
commit 14f1091eb8
4 changed files with 89 additions and 12 deletions

View File

@ -16,10 +16,58 @@ namespace PoweredSoft.DynamicLinq.ConsoleApp
{ {
var type = typeof(Dal.Pocos.Author); var type = typeof(Dal.Pocos.Author);
var param = Expression.Parameter(type); var param = Expression.Parameter(type);
var path = "Posts.Comments.Id"; var parts = ExpressionPathPart.Split(param, "Posts.Comments.Id");
var parts = ExpressionPathPart.Break(param, "Posts.Comments.Id"); // add the last part.
var parent = parts.Last();
var toListType = parent.GetToListType();
parts.Add(new ExpressionPathPart
{
ParentExpression = parent.PartExpression,
PartExpression = Expression.Call(typeof(Enumerable), "ToList", new[] { toListType }, parent.ParentExpression)
});
var result = CreateSelectExpressionFromParts(parts, SelectCollectionHandling.Flatten, SelectNullHandling.New);
}
public static Expression CreateSelectExpressionFromParts(List<ExpressionPathPart> parts,
SelectCollectionHandling selectCollectionHandling = SelectCollectionHandling.LeaveAsIs,
SelectNullHandling nullChecking = SelectNullHandling.LeaveAsIs)
{
Type nullHandlingRightType = null;
Expression nullHandlingNullValue = null;
if (nullChecking != SelectNullHandling.LeaveAsIs)
{
nullHandlingRightType = parts.Last().PartExpression.Type;
nullHandlingNullValue = nullChecking == SelectNullHandling.Default
? Expression.Default(nullHandlingRightType) as Expression
: Expression.New(nullHandlingRightType) as Expression;
}
// reversed :)
var reversedCopy = parts.Select(t => t).ToList();
reversedCopy.Reverse();
Expression ret = null;
reversedCopy.ForEach(t =>
{
if (t.IsParentGenericEnumerable())
{
var lambda = t.GetLambdaExpression();
var parentGenericType = t.ParentGenericEnumerableType();
if (selectCollectionHandling == SelectCollectionHandling.LeaveAsIs || !t.IsGenericEnumerable())
ret = Expression.Call(typeof(Enumerable), "Select", new Type[] { parentGenericType, t.PartExpression.Type }, t.ParentExpression, lambda);
else
ret = Expression.Call(typeof(Enumerable), "SelectMany", new Type[] { parentGenericType, t.GenericEnumerableType() }, t.ParentExpression, lambda);
}
else
{
ret = t.PartExpression;
}
});
return ret;
} }

View File

@ -59,6 +59,13 @@ namespace PoweredSoft.DynamicLinq
Flatten Flatten
} }
public enum SelectNullHandling
{
LeaveAsIs,
Default,
New
}
internal static class Constants internal static class Constants
{ {
internal static readonly MethodInfo GroupByMethod = typeof(Queryable).GetMethods().First(t => t.Name == "GroupBy"); internal static readonly MethodInfo GroupByMethod = typeof(Queryable).GetMethods().First(t => t.Name == "GroupBy");

View File

@ -8,13 +8,18 @@ namespace PoweredSoft.DynamicLinq.Helpers
public class ExpressionPathPart public class ExpressionPathPart
{ {
public Expression ParentExpression { get; set; } public Expression ParentExpression { get; set; }
public Expression Expression { get; set; } public ParameterExpression ParameterExpression { get; set; }
public bool IsNullable() => TypeHelpers.IsNullable(Expression.Type); public Expression PartExpression { get; set; }
public bool IsParentParamaterExpression() => ParentExpression is ParameterExpression;
public bool IsGenericEnumerable() => QueryableHelpers.IsGenericEnumerable(Expression);
public Type GenericEnumerableType() => Expression.Type.GenericTypeArguments.First();
public static List<ExpressionPathPart> Break(ParameterExpression param, string path) public bool IsNullable() => TypeHelpers.IsNullable(PartExpression.Type);
public bool IsGenericEnumerable() => QueryableHelpers.IsGenericEnumerable(PartExpression);
public Type GenericEnumerableType() => PartExpression.Type.GenericTypeArguments.First();
public bool IsCallingMethod() => PartExpression is MethodCallExpression;
public Type GetToListType() => IsGenericEnumerable() ? GenericEnumerableType() : PartExpression.Type;
public bool IsParentGenericEnumerable() => QueryableHelpers.IsGenericEnumerable(ParentExpression);
public static List<ExpressionPathPart> Split(ParameterExpression param, string path)
{ {
var ret = new List<ExpressionPathPart>(); var ret = new List<ExpressionPathPart>();
@ -23,14 +28,31 @@ namespace PoweredSoft.DynamicLinq.Helpers
parts.ForEach(part => parts.ForEach(part =>
{ {
var p = new ExpressionPathPart(); var p = new ExpressionPathPart();
p.Expression = Expression.PropertyOrField(parent, part); p.PartExpression = Expression.PropertyOrField(parent, part);
p.ParentExpression = parent; p.ParentExpression = parent;
p.ParameterExpression = param;
ret.Add(p); ret.Add(p);
parent = p.IsGenericEnumerable() ? Expression.Parameter(p.GenericEnumerableType()) : p.Expression; if (p.IsGenericEnumerable())
{
param = Expression.Parameter(p.GenericEnumerableType());
parent = param;
}
else
{
parent = p.PartExpression;
}
}); });
return ret; return ret;
} }
public LambdaExpression GetLambdaExpression()
{
var lambda = Expression.Lambda(PartExpression, ParameterExpression);
return lambda;
}
public Type ParentGenericEnumerableType() => ParentExpression.Type.GenericTypeArguments.First();
} }
} }

View File

@ -296,11 +296,11 @@ namespace PoweredSoft.DynamicLinq.Helpers
/// <returns></returns> /// <returns></returns>
public static Expression ResolvePathForExpression(ParameterExpression param, string path) public static Expression ResolvePathForExpression(ParameterExpression param, string path)
{ {
var parts = ExpressionPathPart.Break(param, path); var parts = ExpressionPathPart.Split(param, path);
if (parts.Any(t => t.IsGenericEnumerable())) if (parts.Any(t => t.IsGenericEnumerable()))
throw new Exception("this method does not support collection handling"); throw new Exception("this method does not support collection handling");
return parts.Last().Expression; return parts.Last().PartExpression;
} }
public static ConstantExpression GetConstantSameAsLeftOperator(Expression member, object value) public static ConstantExpression GetConstantSameAsLeftOperator(Expression member, object value)