advancing well on a parser concept that can be reused to refactor complicated paths in conditions as well later on (even though it works I think its worth changing later on).

This commit is contained in:
David Lebée
2018-04-05 17:54:28 -05:00
parent 2bd292f18d
commit 327d141c8e
11 changed files with 275 additions and 185 deletions
+1 -2
View File
@@ -62,8 +62,7 @@ namespace PoweredSoft.DynamicLinq
public enum SelectNullHandling
{
LeaveAsIs,
Default,
New
Handle
}
internal static class Constants
@@ -0,0 +1,88 @@
using PoweredSoft.DynamicLinq.Helpers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace PoweredSoft.DynamicLinq.Parser
{
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 static ExpressionParserPiece GetFirstEnumerableParent(ExpressionParserPiece piece)
{
if (piece.Parent == null)
return null;
if (piece.Parent.IsGenericEnumerable)
return piece.Parent;
return GetFirstEnumerableParent(piece.Parent);
}
public void Parse()
{
Pieces.Clear();
var pathPieces = Path.Split('.').ToList();
var param = Parameter;
ExpressionParserPiece parent = null;
pathPieces.ForEach(pp =>
{
var memberExpression = Expression.PropertyOrField(param, pp);
var current = new ExpressionParserPiece
{
Type = memberExpression.Type,
IsGenericEnumerable = QueryableHelpers.IsGenericEnumerable(memberExpression),
EnumerableType = memberExpression.Type.GenericTypeArguments.FirstOrDefault(),
Parent = parent,
Name = pp
};
Pieces.Add(current);
// for next iteration.
param = Expression.Parameter(current.IsGenericEnumerable ? current.EnumerableType : current.Type);
parent = current;
});
}
private ExpressionParserPieceGroup CreateAndAddGroup(List<ExpressionParserPieceGroup> groups, ParameterExpression parameter)
{
var group = new ExpressionParserPieceGroup();
group.ParameterExpression = parameter;
groups.Add(group);
return group;
}
public List<ExpressionParserPieceGroup> GroupBySharedParameters()
{
var groups = new List<ExpressionParserPieceGroup>();
var group = CreateAndAddGroup(groups, Parameter);
Pieces.ForEach(piece =>
{
group.Pieces.Add(piece);
if (piece.IsGenericEnumerable)
group = CreateAndAddGroup(groups, Expression.Parameter(piece.EnumerableType));
});
return groups;
}
}
}
@@ -0,0 +1,18 @@
using System;
namespace PoweredSoft.DynamicLinq.Parser
{
public class ExpressionParserPiece
{
public Type Type { get; set; }
public bool IsGenericEnumerable { get; set; }
public Type EnumerableType { get; set; }
public ExpressionParserPiece Parent { get; set; }
public string Name { get; internal set; }
#if DEBUG
public string DebugPath => $"{Type?.Name} {Name} -> {Parent?.DebugPath ?? "ROOT PARAMETER"}";
public override string ToString() => $"{Type?.Name} {Name}";
#endif
}
}
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
namespace PoweredSoft.DynamicLinq.Parser
{
public class ExpressionParserPieceGroup
{
public List<ExpressionParserPiece> Pieces { get; set; } = new List<ExpressionParserPiece>();
public ParameterExpression ParameterExpression { get; set; }
#if DEBUG
public override string ToString() => $"{ParameterExpression?.ToString()} is {ParameterExpression?.Type} | {(Pieces == null ? "" : string.Join(" -> ", Pieces.Select(t2 => t2.ToString())))}";
public object CompileSimpleExpress(SelectNullHandling nullHandling)
{
throw new NotImplementedException();
}
#endif
}
}
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text;
namespace PoweredSoft.DynamicLinq.Parser
{
public static class ParserExtensions
{
public static ExpressionParserPiece FirstEnumerableParent(this ExpressionParserPiece piece)
{
var result = ExpressionParser.GetFirstEnumerableParent(piece);
return result;
}
public static LambdaExpression CompileGroup(this ExpressionParserPieceGroup group, SelectNullHandling NullHandling)
{
var expr = group.ParameterExpression as Expression;
group.Pieces.ForEach(piece =>
{
expr = Expression.PropertyOrField(expr, piece.Name);
});
var ret = Expression.Lambda(expr, group.ParameterExpression);
return ret;
}
}
}