我有表达式树源于Linq,例如leCollection.Where(...).OrderBy(...).Skip(n).Take(m)
。表达的样子:现在在提供的`Expression'之上添加`MethodCallExpression`
Take(Skip(OrderBy(Where(...), ...), n), m) // you got the idea
,这是我的理想状态,我有Take
和Skip
存在,但它是不是规则。如果需要,我想以编程方式添加Take
/Skip
。
我想出办法如何改变Take
/Skip
的说法,我甚至可以添加Skip
Take
下,如果我发现这是不存在的,但我在努力弄清楚如何在顶部加入Take
的表达 - 我不知道如何识别我实际上访问的顶级表达。我写的方法是在树中的每个方法调用中执行的,所以我必须在对表达式做任何事情之前检查方法名称。
这里是我用来改变Take
/Skip
和在Take
下加Skip
的方法。那些工作,我现在也有兴趣将Take
放在树顶部,如果它还没有出现。任何人都可以指引我到任何智慧的地方,在那里我可以学到更多?
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))
});
}
}