需要一个函数来提供给IEnumerable和IQueryable的Where()方法

3

我有一个如下所示的Func:

Func<Foo, bool> IsSuperhero = x => x.WearsUnderpantsOutsideTrousers;

我可以像这样查询IEnumerables:

IEnumerable<Foo> foos = GetAllMyFoos();
var superFoos = foos.Where(IsSuperhero);

但当我尝试将相同的 Func 提供给 IQueryable 的 Where 方法时,我收到以下错误:

'无法将源类型 System.Collections.Generic.IEnumerable 转换为 System.Linq.IQueryable.'

发生了什么?我如何定义一个可以同时作为 IEnumerable 和 IQueryable 规范的 Func?

1个回答

3

IQueryable 的 LINQ 方法使用 表达式树,而不是普通的委托。

因此,您需要将您的 func 变量更改为 Expression<Func<Foo, bool>>,像这样:

Expression<Func<Foo, bool>> IsSuperhero = x => x.WearsUnderpantsOutsideTrousers;

要在 IEnumerable<T> 中使用相同的变量,您需要调用 AsQueryable()Compile(),如下所示:

IQueryable<Foo> superFoos = foos.AsQueryable().Where(IsSuperhero);
IEnumerable<Foo> superFoos = foos.Where(IsSuperhero.Compile());

但是我不能使用它查询IEnumerables!!!肯定有一种方法可以同时使用相同的规范吧? - David
@David:这种行为是必要的。IQueryable 是为像 LINQ to SQL 这样的事情而设计的,需要找出委托的作用。这在普通的委托中是不可能的,因此它们必须采取一个 Expression<T> - SLaks
哇!我觉得我离理解还有很长的路要走,但是感谢你的指引! :) - David
@David,值得学习更多关于表达式树的知识,因为它们非常酷。它们编码有关表达式“意义”的信息,而不仅仅是生成执行函数的代码。系统可以利用这些信息来做一些有趣、聪明的事情,比如将强类型的.NET表达式转换成标准的SQL查询。 - Dan Bryant
谢谢你解释。我知道它们被用来将一组条件转换为另一种形式(例如SQL或LDAP查询),但是这样做的方式对我来说像在一个遥远、充满魔法的模糊之地。但这并不总是这样! - David
感谢大家的参与。这篇文章对我来说是非常有教育意义的。 - David

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