C# 为什么Queryable.SelectMany(…)重载接受Func<;S、 IEnumerable<;R>&燃气轮机;而不是Func<;S、 IQueryable<;R>>;?
考虑以下功能:C# 为什么Queryable.SelectMany(…)重载接受Func<;S、 IEnumerable<;R>&燃气轮机;而不是Func<;S、 IQueryable<;R>>;?,c#,linq,ienumerable,iqueryable,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; } IQueryable foo(IEnumerable源代码
IQueryable<Bar> foo(IEnumerable<IQueryable<Bar>> sources)
{
return
from source in sources.AsQueryable()
from bar in source
where bar.Xzy == 123
select bar;
}
IQueryable foo(IEnumerable源代码)
{
返回
来自sources.AsQueryable()中的source
源代码中的自条
其中bar.Xzy==123
选择栏;
}
直觉上,我希望它在每个源的上下文中执行“from…where…select”表达式。但是,我相信它只会对源代码执行“from bar in…”部分,而将“where…select”部分作为LINQ to Objects查询执行。最终的结果是,SomeTable的所有行都将从每个源中检索,而不仅仅是那些匹配“where”条件的行
乍一看,我猜想这是因为调用SelectMany会导致“source”表达式隐式转换为IEnumerable。我不确定实现是什么样子的,但是它接受Func,这样where…select表达式就被传递给IQueryable提供程序,这难道没有意义吗?我认为这取决于编译器如何解释您的查询。它实际上将查询转化为如下内容(严格的从左到右解析): 至关重要的是,您的过滤器首先对枚举每个源的结果进行操作 还要注意,
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
出于这个原因,我通常倾向于使用扩展方法手工创建非平凡的查询。源代码的类型是什么。SomeTable?如果将
foo
的返回类型更改为IQueryable
,会发生什么情况?@Lee,对不起,我认为SomeTable属性在示例中没有意义。我将“source.SomeTable”改为“source”。我认为将返回类型更改为IQueryable不会改变查询的行为。返回类型应该有所不同,因为IEnumerable
重载返回IEnumerable
,而IQueryable
重载返回IQueryable
。因此,如果返回类型更改为IQueryable
,并且选择了SelectMany
的IEnumerable
重载,则函数将无法编译。@Lee,我不太明白你的意思。“IEnumerable重载”指的是什么?我认为该方法中的查询表达式的类型是IQueryable,它也实现了IEnumerable,因此我不确定为什么它很重要,除非foo的调用方将返回值传递给其他LINQ方法。接受IEnumerable作为选择器是一个设计决策。你只是在问为什么做出这个决定吗?谢谢,我最后使用了一个LINQ表达式,就像你更新的答案一样。我只是想弄明白为什么最初的查询没有达到我的预期。我最初在我的“real”查询中添加了AsQueryable()调用,它认为通过强制使用Queryable.SelectMany而不是Enumerable.SelectMany可以解决我的问题(它没有)。
from source in sources
let qsource = (from bar in source
where bar.Xzy == 123
select bar)
from result in qsource
select result