动态LINQ的Select函数适用于Enumerable,但不适用于Queryable。

3

我已经玩弄动态LINQ有一段时间了,但是我还没有学会它的秘密。

我想解析的表达式如下所示:

"document.LineItems.Select(i => i.Credit).Sum();"

在解析过程中,我需要对LineItems Collection调用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?]

目前还没有实现任何东西。我只是在建立表达式树。

问题是:

这个Expression.Call抛出了一个异常:"类型'System.Linq.Queryable'上没有泛型方法'Select'与提供的类型参数和参数兼容";

我很容易地通过在Expression.Call的第一个参数中查找'Select'时改为在'System.Linq.Enumerable'中查找而不是'Queryable'来解决它。

但是,这并不完全是我想要的。我不想将所有LineItems都拉进来,只是为了计算Sum(),这显然是使用Enumerable的情况。我想让Queryable工作。

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

我已经检查了MSDN,“Select”函数的两个签名是相同的,所以我真的看不出为什么一个会起作用而另一个不会。

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

问候,

1个回答

4
问题在于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);
}

很好的答案,我就猜到会是这样。我甚至尝试在LineItems集合上调用AsQueryable,但它并没有帮助我。我怎样才能安全地将expr更改为IQueryable? - Milos Mijatovic
@MilosMijatovic - 我认为 AsQueryable 应该可以工作,我已经更新了答案并包含了一个示例。 - Lee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接