我的表达树起源于Linq,例如Trying ::1...
TCP_NODELAY set
Connected to localhost (::1) port 8080 (#0)
GET /mydataset/page/def/sector-publico/contrato/cod-centro-destino HTTP/1.1
Host: localhost:8080
User-Agent: curl/7.53.1
Accept: application/rdf+xml
HTTP/1.1 200
Cache-Control: no-cache
Pragma: no-cache
Content-Type: text/html;charset=utf-8
Content-Length: 4341
Date: Sat, 14 Oct 2017 16:55:21 GMT
。表达式如下:
leCollection.Where(...).OrderBy(...).Skip(n).Take(m)
现在,这是我理想的状态,我有Take(Skip(OrderBy(Where(...), ...), n), m) // you got the idea
和Take
,但这不是规则。如果需要,我想以编程方式添加Skip
/ Take
。
我想出了如何更改Skip
/ Take
参数,如果我检测到它,我甚至可以在Skip
下添加Skip
&# 39;不存在,但我正在努力弄清楚如何在表达的顶部添加Take
- 我不知道如何识别我实际上正在访问顶级表达。我编写的方法是在树中的每个方法调用上执行的,所以在我对表达式执行任何操作之前,我必须检查方法名称。
以下是我用于更改Take
/ Take
并在Skip
下添加Skip
的方法。这些工作,我现在也有兴趣将Take
置于树顶,如果它还没有出现的话。谁能指引我到任何智慧的地方,在那里我可以学到更多东西?
Take
答案 0 :(得分:1)
您可以覆盖Visit
方法并使用flag变量来检查这是否是第一次调用它
下一个代码会检查一个top方法,如果它不是Take
添加对Queryable.Take
的调用
public class AddTakeVisitor : ExpressionVisitor
{
private readonly int takeAmount;
private bool firstEntry = true;
public AddTakeVisitor(int takeAmount)
{
this.takeAmount = takeAmount;
}
public override Expression Visit(Expression node)
{
if (!firstEntry)
return base.Visit(node);
firstEntry = false;
var methodCallExpression = node as MethodCallExpression;
if (methodCallExpression == null)
return base.Visit(node);
if (methodCallExpression.Method.Name == "Take")
return base.Visit(node);
var elementType = node.Type.GetGenericArguments();
var methodInfo = typeof(Queryable)
.GetMethod("Take", BindingFlags.Public | BindingFlags.Static)
.MakeGenericMethod(elementType.First());
return Expression.Call(methodInfo, node, Expression.Constant(takeAmount));
}
}
我用这段代码测试了它:
var exp = (new[] {1, 2, 3}).AsQueryable().Skip(1);
var visitor = new AddTakeVisitor(1);
var modified = visitor.Visit(exp.Expression);
modified.DebugView
看起来像这样:
.Call System.Linq.Queryable.Take(
.Call System.Linq.Queryable.Skip(
.Constant<System.Linq.EnumerableQuery`1[System.Int32]>(System.Int32[]),
1),
1)