IQueryable 和 IEnumerable 有啥区别 [重复]

Posted

技术标签:

【中文标题】IQueryable 和 IEnumerable 有啥区别 [重复]【英文标题】:What's the difference between IQueryable and IEnumerable [duplicate]IQueryable 和 IEnumerable 有什么区别 [重复] 【发布时间】:2011-01-26 20:37:48 【问题描述】:

我对区别感到困惑。作为.Net 的新手,我知道我可以使用Linq 扩展查询IEnumerables。那么这是什么IQueryable,它有什么不同呢?


另请参阅与此问题重叠的What is the difference between IQueryable[T] and IEnumerable[T]?。

【问题讨论】:

【参考方案1】:

IEnumerable<T> 表示T 的只进游标。 .NET 3.5 添加了包括LINQ standard query operators 的扩展方法,如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 =&gt; x.Age &gt; 18 是一个匿名方法 (Func&lt;Person, bool&gt;),它可以像任何其他方法一样执行。 Enumerable.Where 将为每个人执行一次该方法,yielding 方法返回的值是 true

在第二个块中,x =&gt; x.Age &gt; 18 是一个表达式树(Expression&lt;Func&lt;Person, bool&gt;&gt;),可以认为是“是 'Age' 属性 > 18”。

这允许诸如 LINQ-to-SQL 之类的东西存在,因为它们可以解析表达式树并将其转换为等效的 SQL。并且由于提供者在IQueryable被枚举之前不需要执行(毕竟它实现了IEnumerable&lt;T&gt;),它可以组合多个查询运算符(在上面的例子中WhereFirstOrDefault)变得更智能选择如何针对底层数据源执行整个查询(例如在 SQL 中使用 SELECT TOP 1)。

见:

The .NET Standard Query Operators

【讨论】:

【参考方案2】:

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

如果创建IQueryable,则查询可能会转换为sql并在数据库服务器上运行 如果您创建IEnumerable,则在运行查询之前,所有行都将作为对象拉入内存。

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

如果你扩展你的查询:

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

然后使用IQueryable 生成的SQL 将包含where name = "a",但使用IEnumerable 将从数据库中拉回更多角色,然后x.name = "a" 检查将由.NET 完成。

【讨论】:

“查询可能被转换为 sql”:我没有得到“可能”。此外,如果我有一个 IEnumerable 并创建一个“复杂链”,那么(显然)与 IQueryable 不同,它不会被转换为一个“优化的”SQL 查询。只是想确认当您说“所有行都将被拉入内存”时是什么意思。假设我有两个 where 子句,那么首先将实体的所有元组提取到内存中,然后进行正常的“内存中”过滤吗?【参考方案3】:

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

来源:here

【讨论】:

【参考方案4】:

IEnumerable IEnumerable 最适合使用内存收集。 IEnumerable 不会在项目之间移动,它只是向前的集合。

可查询 IQueryable 最适合远程数据源,如数据库或 Web 服务。 IQueryable 是一个非常强大的功能,它支持各种有趣的延迟执行场景(如基于分页和组合的查询)。

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

【讨论】:

【参考方案5】:

主要区别在于 IEnumerable 将始终枚举其所有元素,而 IQueryable 将根据查询枚举元素,甚至做其他事情。查询是一个表达式(.Net 代码的数据表示形式),IQueryProvider 必须探索/解释/编译/任何内容才能生成结果。

拥有查询表达式有两个好处。

第一个优势是优化。因为查询表达式中包含诸如“Where”之类的修饰符,所以 IQueryProvider 可以应用其他不可能的优化。提供者可以使用哈希表来定位具有给定键的项目,而不是返回所有元素然后由于“Where”子句而丢弃大部分元素。

第二个优势是灵活性。因为表达式是可探索的数据结构,您可以执行诸如序列化查询并将其发送到远程机器(例如 linq-to-sql)等操作。

【讨论】:

【参考方案6】:

IQueriable 与 IEnumerable 相同,但它还提供了额外的功能来使用 Linq 实现自定义查询。以下是 MSDN 上的描述:http://msdn.microsoft.com/en-us/library/system.linq.iqueryable.aspx

【讨论】:

以上是关于IQueryable 和 IEnumerable 有啥区别 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

IQueryable 和 IEnumerable 有啥区别 [重复]

IEnumerable 和 IQueryable

IQueryable 和 IEnumerable 之间差异的真实示例? [复制]

IQueryable和IEnumerable,IList的区别

C# IQueryable和IEnumerable的区别

我的 Entity Framework 存储库和服务层方法应返回哪些类型:List、IEnumerable、IQueryable?