动态LINQ,选择功能,可以枚举,但不可查询 [英] Dynamic LINQ, Select function, works on Enumerable, but not Queryable
问题描述
我一直在动摇LINQ一段时间,但我还没有学习它的秘密。
我有一个表达式,我想解析那个样子像这样:
document.LineItems.Select(i =&i; i.Credit).Sum()
在解析期间,我到达了一个需要在LineItems集合上调用Select函数的点。我使用Expression.Call的工厂方法:
Expression.Call(
typeof(Queryable),
Select,
new Type [] {typeof(LineItem),typeof(decimal?)},
expr,
Expression.Lambda(expression,new ParameterExpression [] {Expression.Parameter (typeof(LineItem)}));
此刻
expr:document.LineItems [ICollection< LineItem>]
表达式:LineItem.Credit [decimal?]
目前还没有实现,我只是在构建表达式树。
现在,问题:
此Expresssion.Call抛出和异常:无通用方法'选择'类型'System.Linq.Queryable'与提供的类型兼容参数和参数;
我可以通过在System.Linq.Enumerable中查找Select,而不是可查询来解决它愤怒的第一个参数Expression.Call。
但是,这不是我想要的。我不希望所有LineItems只能计算Sum(),这显然是Enumerable的情况。我想要Queryable工作。
另外,对于解析的最后一部分 - Sum(),我还需要使用Enumerable Sum(),因为Queryable Sum()抛出相同的异常。
我已经检查了MSDN,选择功能的两个签名都是相同的,所以我真的看不出为什么一个工作和其他工作。 >
任何帮助或指针将被aprreciated。
注意,
问题是 LineItems
是一个 ICollection< LineItem>
而 Queryable.Select
的第一个参数需要一个 IQueryable< LineItem>
。 ICollection< T>
仅实现 IEnumerable< T>
,这就是为什么它适用于 Enumerable。选择
。
您需要将 expr
的类型更改为<$你可以使用 Queryable.AsQueryable / code>方法。以下函数创建一个表达式来计算给定的
文档
实例的信用属性值:
code> public static Expression< Func< decimal?>>> CreateSumLineItemsExpr(Document document)
{
var docExpr = Expression.Constant(document);
var itemsExpr = Expression.Property(docExpr,LineItems);
表达式< Func< LineItem,decimal?>>> selector = i => i.Credit;
var queryableExpr = Expression.Call(typeof(Queryable),AsQueryable,new [] {typeof(LineItem)},itemsExpr);
var selectExpr = Expression.Call(typeof(Queryable),Select,new [] {typeof(LineItem),typeof(decimal?)},queryableExpr,selector);
var sumExpr = Expression.Call(typeof(Queryable),Sum,null,selectExpr);
返回Expression.Lambda}
I have been fiddling with dynamic LINQ for some time now, but I have yet to learn its secrets.
I have an expression that I want to parse that looks like this:
"document.LineItems.Select(i => i.Credit).Sum();"
During parsing of this I reach a point where I need to call a Select function on LineItems Collection. I am using factory method of Expression.Call:
Expression.Call(
typeof(Queryable),
"Select",
new Type[] { typeof(LineItem), typeof(decimal?) },
expr,
Expression.Lambda(expression, new ParameterExpression[] { Expression.Parameter(typeof(LineItem) }));
At this moment
expr: document.LineItems [ICollection<LineItem>]
expression: LineItem.Credit [decimal?]
none of which is materialized yet. I am just building Expression Tree at the moment.
Now, the problem:
This Expresssion.Call throws and Exception: "No generic method 'Select' on type 'System.Linq.Queryable' is compatible with the supplied type arguments and arguments";
I resolve it easily by looking for 'Select' in 'System.Linq.Enumerable' instead of 'Queryable' by changing first argument of Expression.Call.
But, that's not quite that I want. I don't want all LineItems hauled in only to calculate Sum(), which would obviously be case with Enumerable. I want Queryable to work.
Also, for the last part of parsing - Sum(), I also need to go with Enumerable Sum(), because Queryable Sum() throws same Exception.
I have checked MSDN, both signatures of 'Select' function are identical, so i really cannot see why would one work and other not.
Any help or pointers would be aprreciated.
Regards,
The problem is that LineItems
is an ICollection<LineItem>
, while the first parameter to Queryable.Select
requires an IQueryable<LineItem>
. ICollection<T>
only implements IEnumerable<T>
which is why it works for Enumerable.Select
.
You will need to change the type of expr
to be IQueryable<LineItem>
.
You should be able to do this with the Queryable.AsQueryable
method. The following function creates an expression to sum the credit property values for a given Document
instance:
public static Expression<Func<decimal?>> CreateSumLineItemsExpr(Document document)
{
var docExpr = Expression.Constant(document);
var itemsExpr = Expression.Property(docExpr, "LineItems");
Expression<Func<LineItem, decimal?>> selector = i => i.Credit;
var queryableExpr = Expression.Call(typeof(Queryable), "AsQueryable", new[] { typeof(LineItem) }, itemsExpr);
var selectExpr = Expression.Call(typeof(Queryable), "Select", new[] { typeof(LineItem), typeof(decimal?) }, queryableExpr, selector);
var sumExpr = Expression.Call(typeof(Queryable), "Sum", null, selectExpr);
return Expression.Lambda<Func<decimal?>>(sumExpr);
}
这篇关于动态LINQ,选择功能,可以枚举,但不可查询的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!