为什么Queryable.SelectMany(...)重载接受Func <s,ienumerable <r =“”>&gt;而不是Func <s,iqueryable <r =“”>&gt;?

时间:2016-05-06 16:32:49

标签: c# linq ienumerable iqueryable

考虑以下功能:

IQueryable<Bar> foo(IEnumerable<IQueryable<Bar>> sources)
{
    return
        from source in sources.AsQueryable()
        from bar in source
        where bar.Xzy == 123
        select bar;
}

直观地说,我希望这可以执行&#34; from ... where ... select&#34;在每个来源的上下文中表达。但是,我相信它只会在...中执行&#34;来自...&#34;反对来源的部分,而是执行&#34;其中... select&#34;部分作为LINQ到对象查询。最终结果是SomeTable的所有行都将从每个源中检索,而不是仅仅匹配&#34;其中&#34;条件。

乍一看,我的猜测是,这是因为对SelectMany的调用会导致&#34;来源&#34;要隐式转换为IEnumerable&lt; Bar&gt;的表达式。我不确定实现是什么样的,但是它接受Func&lt; S,IQueryable&lt; R&gt;&gt;是不合理的了。相反,所以where ... select表达式被传递给IQueryable提供者?

1 个答案:

答案 0 :(得分:1)

我认为这取决于编译器如何解释您的查询。实际上你的查询是什么就是这样的(一个严格的从左到右的解析):

sources.AsQueryable()
       .SelectMany(source => source)
       .Where(bar => bar.Xzy == 123)
       .Select(bar => bar)

至关重要的是,您的过滤器会先对每个来源进行枚举。

另请注意,AsQueryable()实际上是多余的,因为它不会使您的来源比现有的更具可查询性,它使您的源的枚举可查询,而且您无论如何都不是在询问那个集合,你是在查询各个来源。

我认为你真正想要的更像是这样:

sources.SelectMany(source => source.Where(bar => bar.Xzy == 123))

这改变了对条款的相对“优先顺序”的解释。

我实际上不确定如何使用LINQ语法制作后者。

更新:实际上,这是一种方式:

from source in sources
let qsource = (from bar in source
               where bar.Xzy == 123
               select bar)
from result in qsource
select result

由于这个原因,我通常倾向于使用扩展方法来制作非平凡的查询。