I'm having expression tree originating in Linq, e.g. leCollection.Where(...).OrderBy(...).Skip(n).Take(m)
. Expression looks like:
Take(Skip(OrderBy(Where(...), ...), n), m) // you got the idea
Now, this is my ideal state that I have Take
and Skip
there, but it is not the rule. I would like to add Take
/Skip
programmatically if needed.
I came up with way how to change Take
/Skip
argument, and I'm even able to add Skip
under Take
if I detect it's not present, but I'm struggling to figure out how to add Take
at the top of expression - I don't know how to recognize I'm actually visiting top expression. Methods I wrote are executed on every method call in tree, so I had to check method name before I do anything with expression.
Here are methods I'm using for altering Take
/Skip
and adding Skip
under Take
. Those work, I'm now also interested in placing Take
on top of tree if it's not yet present. Could anyone direct me to any place of wisdom, where I can learn more?
public class LeVisitor<TEntity> : ExpressionVisitor
where TEntity : class
{
private readonly int? _take;
private readonly int? _skip;
private readonly MethodInfo _queryableSkip;
public LeVisitor(int? take, int? skip)
{
// ...
}
protected override Expression VisitMethodCall(MethodCallExpression node)
{
return base.VisitMethodCall(AlterTake(AlterSkip(node)));
}
private MethodCallExpression AlterTake(MethodCallExpression node)
{
if (!_take.HasValue || !node.Method.Name.Equals("Take", StringComparison.Ordinal))
{
return node;
}
Expression innerCall = node.Arguments[0];
if (_skip != null)
{
var innerMethod = innerCall as MethodCallExpression;
if (innerMethod != null && !innerMethod.Method.Name.Equals("Skip", StringComparison.Ordinal))
{
ConstantExpression skipConstant = Expression.Constant(_skip, typeof(int));
innerCall = Expression.Call(_queryableSkip, new[] { innerCall, skipConstant });
}
}
return node.Update(
node.Object,
new[]
{
innerCall,
Expression.Constant(_take, typeof(int))
});
}
private MethodCallExpression AlterSkip(MethodCallExpression node)
{
if (!_skip.HasValue || !node.Method.Name.Equals("Skip", StringComparison.Ordinal))
{
return node;
}
return node.Update(
node.Object,
new[]
{
node.Arguments[0],
Expression.Constant(_skip, typeof(int))
});
}
}
Aucun commentaire:
Enregistrer un commentaire