select, group, where, orderby这4个语句比较简单,调用的扩展方法参数形式都近似,处理的方式都是先得到语句的表达式然后把上一个参数代入,调用相应的扩展方法,这里用一个统一的处理方法来进行处理:
private Expression GetQueryExpression(string op, ParseTreeNode expNode, bool inhiretParameter = false)
{
var lastVariable = _linqVariables.Peek();
EnterScope(new[] { lastVariable.NextParameter });
var queryBody = ProcessExpression(expNode);
LeaveScope();
var exp = Expression.Call(MakeMethod(op, lastVariable.NextParameter.Type, queryBody.Type),
lastVariable.Self,
Expression.Lambda(queryBody, lastVariable.NextParameter));
var newVariable = new LINQContext
{
Parameter = lastVariable.NextParameter,
Name = GetTransparentIdentifier(),
Self = exp,
};
if (inhiretParameter)
newVariable.NextParameter = lastVariable.NextParameter;
_linqVariables.Push(newVariable);
return exp;
}
要注意的是默认linqcontext的NextParameter是当前Self的ElementType,而where和orderby的Self的ElementType是bool类型(因为这2个语句的参数表达式都要求返回bool类型),所以这个方法用第三个参数确保where,orderby的NextParameter用的是上一个语句的NextParameter。
select, group的处理部分:
case "query_end_expression":
var child = expNode.FirstChild;
return GetQueryExpression(op, child.LastChild);
一句linq必须是以select或者group作为结尾(group into不在这里处理),这2个语句都被我们的grammar归类到query_end_expression里了。
group into是单独处理的,group into实质上就是先group再select,分析步骤还是很简单的这里就直接上代码了:
case "query_groupinto_expression":
var group = expNode.FirstChild;
op = group.FindTokenAndGetText();
GetQueryExpression(op, group.LastChild);
var into = expNode.LastChild;
var intoid = into.LastChild.FindTokenAndGetText();
op = "select";
last = _linqVariables.Peek();
var grouptype = last.Self.GetElementType();
var intoparameter = Expression.Parameter(grouptype, intoid);
var intoexp = Expression.Call(MakeMethod(op, grouptype, grouptype),
last.Self,
Expression.Lambda(intoparameter, intoparameter));
_linqVariables.Push(new LINQContext
{
Parameter = intoparameter,
Name = intoparameter.Name,
Self = intoexp,
});
break;
where的处理部分:
case "query_where_expression":
GetQueryExpression(op, expNode.LastChild, true);
break;
第三个参数为true,表示用上一个语句的NextParameter作为当前NextParameter给下一句linq进行调用。
orderby处理部分:
case "query_orderby_expression":
var orderbylist = expNode.GetChild("query_orderby_list");
for (int i = 0; i < orderbylist.ChildNodes.Count; ++i)
{
var orderchild = orderbylist.ChildNodes[i];
var order = orderchild.GetChild("query_orderby_order");
var orderind = "ascending";
if (order != null)
orderind = order.FindTokenAndGetText();
if (i > 0)
op = "thenby";
op += orderind == "ascending" ? String.Empty : orderind;
GetQueryExpression(op, orderchild.FirstChild, true);
}
break;
orderby需要用到4个扩展方法进行处理,
extensionMethods["orderby"] = typeof(Queryable).GetExtensionMethod("OrderBy", typeof(IQueryable<>), typeof(Expression<>).MakeGenericType(typeof(Func<,>)));
extensionMethods["orderbydescending"] = typeof(Queryable).GetExtensionMethod("OrderByDescending", typeof(IQueryable<>), typeof(Expression<>).MakeGenericType(typeof(Func<,>)));
extensionMethods["thenby"] = typeof(Queryable).GetExtensionMethod("ThenBy", typeof(IOrderedQueryable<>), typeof(Expression<>).MakeGenericType(typeof(Func<,>)));
extensionMethods["thenbydescending"] = typeof(Queryable).GetExtensionMethod("ThenByDescending", typeof(IOrderedQueryable<>), typeof(Expression<>).MakeGenericType(typeof(Func<,>)));
除orderby的第一个参数是用orderby作为调用方法外,后面都用thenby方法作连接。