J'ai un arbre d'expression provenant de Linq, par ex. leCollection.Where(...).OrderBy(...).Skip(n).Take(m)
. L'expression ressemble à:Ajout de `MethodCallExpression` au-dessus de` Expression` fournie
Take(Skip(OrderBy(Where(...), ...), n), m) // you got the idea
Maintenant, c'est mon état idéal que j'ai là Take
et Skip
, mais ce n'est pas la règle. Je voudrais ajouter Take
/Skip
par programme si nécessaire.
je suis venu avec la manière comment changer Take
argument/Skip
, et je suis même en mesure d'ajouter Skip
sous Take
si je perçois ce n'est pas présent, mais je suis mal à comprendre comment ajouter Take
en haut d'expression - Je ne sais pas comment reconnaître que je suis en train de visiter la meilleure expression. Les méthodes que j'ai écrites sont exécutées sur chaque appel de méthode dans l'arbre, donc j'ai dû vérifier le nom de la méthode avant de faire quoi que ce soit avec l'expression.
Voici les méthodes que je utilise pour modifier Take
/Skip
et en ajoutant Skip
sous Take
. Ceux qui travaillent, je suis également intéressé à placer Take
sur l'arbre s'il n'est pas encore présent. Quelqu'un pourrait-il me diriger vers n'importe quel endroit de la sagesse, où je peux apprendre plus?
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))
});
}
}