问题
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,
回答1:
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);
}
来源:https://stackoverflow.com/questions/13777781/dynamic-linq-select-function-works-on-enumerable-but-not-queryable