IQueryable和IEnumerable有什么区别?

158
6个回答

196

IEnumerable<T> 代表了一个 T 的只向前游标。.NET 3.5 添加了扩展方法,其中包括 LINQ 标准查询操作符,如 WhereFirst,任何需要谓词或匿名函数的操作符都采用 Func<T>

IQueryable<T> 实现了相同的 LINQ 标准查询操作符,但接受 Expression<Func<T>> 作为谓词和匿名函数。 Expression<T> 是一个已编译的表达式树,是方法的分解版本(如果您愿意,可以说是“半编译的”),可由查询提供程序解析并相应地使用。

例如:

IEnumerable<Person> people = GetEnumerablePeople();
Person person = people.Where(x => x.Age > 18).FirstOrDefault();

IQueryable<Person> people = GetQueryablePeople();
Person person = people.Where(x => x.Age > 18).FirstOrDefault();

在第一个块中,x => x.Age > 18 是一个匿名方法 (Func<Person, bool>),可以像其他方法一样执行。 Enumerable.Where 将为每个人执行该方法,yield 返回方法返回 true 的值。
在第二个块中,x => x.Age > 18 是一个表达式树 (Expression<Func<Person, bool>>),可以认为是“'Age' 属性是否大于 18”。
这使得类似于 LINQ-to-SQL 的东西存在,因为它们可以解析表达式树并将其转换为等效的 SQL。而且,由于提供程序不需要执行直到枚举 IQueryable(毕竟它实现了 IEnumerable<T>),它可以组合多个查询运算符(在上面的示例中是 WhereFirstOrDefault)以更智能的方式执行整个查询对基础数据源(如在 SQL 中使用 SELECT TOP 1)。
请参见:

91

在现实生活中,如果您使用像LINQ-to-SQL这样的ORM

  • 如果您创建一个IQueryable,则查询可能会转换为SQL并在数据库服务器上运行
  • 如果您创建一个IEnumerable,则在运行查询之前,所有行将作为对象加载到内存中。

在这两种情况下,如果您不调用ToList()ToArray(),则每次使用查询时都会执行查询,因此,假设您有一个IQueryable,并从中填充4个列表框,则查询将针对数据库运行4次。

另外,如果您扩展查询:

q.Select(x.name = "a").ToList()

如果使用 IQueryable,生成的SQL语句将包含 where name = "a",但如果使用 IEnumerable,将从数据库中获取更多的内容,然后由 .NET 进行 x.name = "a" 的检查。


查询可能会被转换为SQL,我不明白“可能会”是什么意思。此外,如果我有一个IEnumerable并创建了一个“复杂链”,那么(显然)与IQueryable不同,它不会被转换为“优化”的SQL查询。只想确认一下,当您说“所有行将被提取到内存中”时,这是什么意思?假设我有两个where子句,那么实体的所有元组是否都会首先被提取到内存中,然后进行普通的“内存中”过滤? - Vaibhav

38

主要区别在于 IQueryable 定义的扩展方法接受 Expression 对象而不是 Func 对象,这意味着它接收的委托是一个表达式树而不是一个要调用的方法。IEnumerable 在处理内存集合方面非常出色,但 IQueryable 允许使用远程数据源,如数据库或 Web 服务。

来源:这里


21

IEnumerable IEnumerable适用于处理内存中的集合。 IEnumerable不会在项之间移动,它只能向前移动。

IQueryable IQueryable最适合远程数据源,比如数据库或Web服务。 IQueryable是一项非常强大的功能,支持多种有趣的延迟执行方案(例如分页和基于组合的查询)。

因此,当您需要简单地遍历内存中的集合时,请使用IEnumerable;如果您需要对集合进行任何操作,例如DataSet和其他数据源,请使用IQueryable。


11

主要区别在于IEnumerable会一直枚举它的所有元素,而IQueryable会根据查询枚举元素或执行其他操作。查询是一个表达式(.Net代码的数据表示),必须由IQueryProvider进行探索/解释/编译/其他以生成结果。

有一个查询表达式具有两个优点。

第一个优点是优化。因为类似“Where”的修饰符包含在查询表达式中,所以IQueryProvider可以应用否则无法进行的优化。而不是返回所有元素然后由于'Where'子句而扔掉大部分元素,提供程序可以使用哈希表来定位具有给定键的项。

第二个优点是灵活性。因为表达式是可探索的数据结构,所以您可以做像将查询序列化并将其发送到远程机器(例如linq-to-sql)这样的事情。


1

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