一段时间以来,我一直在摆弄动态 LINQ,但我还没有了解它的 secret 。

我有一个我想解析的表达式,如下所示:

"document.LineItems.Select(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>]
expression:    LineItem.Credit       [decimal?]

目前还没有实现。我现在只是在构建表达式树。

现在,问题:

此 Expresssion.Call 抛出异常:“没有泛型方法 'Select' on type 'System.Linq.Queryable' 与提供的类型参数和参数兼容”;

我通过更改 Expression.Call 的第一个参数,在“System.Linq.Enumerable”中查找“Select”而不是“Queryable”来轻松解决它。

但是,这并不完全是我想要的。我不希望所有的 LineItem 都只用于计算 Sum(),这显然是 Enumerable 的情况。我想让 Queryable 工作。

此外,对于解析的最后一部分 - Sum(),我还需要使用 Enumerable Sum(),因为 Queryable Sum() 抛出相同的异常。

我检查了 MSDN,'Select' 函数的两个签名是相同的,所以我真的不明白为什么一个会工作而另一个不工作。

任何帮助或指示将不胜感激。

问候,

最佳答案

问题是 LineItems 是一个 ICollection<LineItem> ,而 Queryable.Select 的第一个参数需要一个 IQueryable<LineItem>ICollection<T> 只实现 IEnumerable<T> 这就是为什么它适用于 Enumerable.Select

您需要将 expr 的类型更改为 IQueryable<LineItem>

您应该可以使用 Queryable.AsQueryable 方法执行此操作。以下函数创建一个表达式来对给定 Document 实例的信用属性值求和:

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);
}

关于c# - 动态 LINQ,选择函数,适用于可枚举,但不可查询,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13777781/

10-13 00:01