【问题标题】:Dynamic LINQ, Select function, works on Enumerable, but not Queryable动态 LINQ,Select 函数,适用于 Enumerable,但不适用于 Queryable
【发布时间】:2012-11-26 11:58:11
【问题描述】:

我研究动态 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?]

这些都还没有实现。我现在只是在构建表达式树。

现在问题来了:

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

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

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

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

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

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

问候,

【问题讨论】:

    标签: c# linq iqueryable expression enumerable


    【解决方案1】:

    问题在于LineItemsICollection&lt;LineItem&gt;,而Queryable.Select 的第一个参数需要IQueryable&lt;LineItem&gt;ICollection&lt;T&gt; 只实现了IEnumerable&lt;T&gt;,这就是它适用于Enumerable.Select 的原因。

    您需要将expr 的类型更改为IQueryable&lt;LineItem&gt;

    您应该可以使用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?
    • @MilosMijatovic - 我认为AsQueryable 应该可以工作,我已经更新了答案以包含一个示例。
    猜你喜欢
    • 2021-01-23
    • 2019-06-28
    • 1970-01-01
    • 1970-01-01
    • 2020-08-26
    • 1970-01-01
    • 1970-01-01
    • 2013-05-24
    • 2015-09-09
    相关资源
    最近更新 更多