IQueryable <T>和IEnumerable <T>有什么区别?


Answers:


258

首先,扩展的接口,因此任何你可以做一个“普通” ,你也可以用做。IQueryable<T> IEnumerable<T>IEnumerable<T>IQueryable<T>

IEnumerable<T>只是有一个GetEnumerator()返回的方法,Enumerator<T>您可以为其调用MoveNext()方法以迭代T序列。

什么IQueryable<T>具有IEnumerable<T> 是特别酮两个属性指向一个查询提供(例如,LINQ到SQL提供商)和另一个指向一个查询表达式表示所述IQueryable<T>对象作为运行时间横越抽象语法树,可以是给定的查询提供程序可以理解(在大多数情况下,除非抛出异常,否则您不能将LINQ to SQL表达式提供给LINQ to Entities提供程序)。

该表达式可以只是对象本身的常量表达式,也可以是由查询运算符和操作数组成的一组更复杂的树。使用传递给它的表达式调用查询提供程序的IQueryProvider.Execute()IQueryProvider.CreateQuery()方法,然后分别返回查询结果或另一个。IQueryable


8
使用AsQueryable有什么好处?
约旦

6
唯一的好处就是方便。AsQueryable()只会将可枚举类型转换为可查询类型,并在实现IQueryable接口时将其返回,否则将其包装在ConstantExpression,该EnumerableQuery对象在返回的对象中引用 。
马克·西达德


1
值得阅读这篇文章
JenonD


201

主要的区别是,该运营商LINQ为IQueryable<T>Expression对象而不是代表,这意味着它接收自定义查询的逻辑,例如,谓词或值选择器,是一个表达式树,而不是一个委托的方法的形式。

  • IEnumerable<T> 非常适合处理在内存中迭代的序列,但是
  • IQueryable<T> 允许内存不足之类的东西,例如远程数据源,例如数据库或Web服务。

查询执行:

  • 要在“正在处理中”执行查询的地方,通常所需要做的只是执行查询的每个部分的代码(作为代码)。

  • 如果执行将在进程外执行,则查询的逻辑必须以数据表示,以便LINQ提供程序可以将其转换为适合内存不足执行的形式-无论是LDAP查询, SQL或其他。

更多内容:

http://www.codeproject.com/KB/cs/646361/WhatHowWhere.jpg


14
我喜欢提到内存不足的操作。它阐明了实际使用中的实际差异。
Ishmael Smyrnow 2011年

2
IQueryable <T>将采用Expression <TDelegate>参数,而不是像IEnumerable <T> where方法那样将委托作为参数。我们没有将代码传递给IQueryable <T>,而是将表达式树(作为数据的代码)传递给LINQ提供程序进行分析。C#3.0和LINQ
Lu55 2012年

图片链接出现问题,由于某种原因其未在帖子正文中呈现codeproject.com/KB/cs/646361/WhatHowWhere.jpg
jbooker

@joey但是,我在该答案中看到的图像很好:i.stack.imgur.com/2DAqv.jpg
VonC

190

这是youtube上的精彩视频,展示了这些界面的不同之处,值得一看。

下面为它提供了一个长的描述性答案。

要记住的第一个重要点是IQueryable接口继承自IEnumerable,因此无论IEnumerable做什么,IQueryable也可以做到。

在此处输入图片说明

差异很多,但让我们讨论一个最大的差异。IEnumerable当您使用LINQ或Entity Framework 加载集合时,并且您想在集合上应用过滤器时,界面非常有用。

考虑下面IEnumerable与实体框架一起使用的简单代码。它使用一个Where过滤器来获得其记录EmpId2

EmpEntities ent = new EmpEntities();
IEnumerable<Employee> emp = ent.Employees; 
IEnumerable<Employee> temp = emp.Where(x => x.Empid == 2).ToList<Employee>();

该过滤器在IEnumerable代码所在的客户端执行。换句话说,所有数据都是从数据库中获取的,然后在客户端对其进行扫描并获得EmpIdis 的记录2

在此处输入图片说明

但是,现在请看下面的代码,我们将其更改IEnumerableIQueryable。它在服务器端创建一个SQL查询,并且仅将必要的数据发送到客户端。

EmpEntities ent = new EmpEntities();
IQueryable<Employee> emp = ent.Employees;
IQueryable<Employee> temp =  emp.Where(x => x.Empid == 2).ToList<Employee>();

在此处输入图片说明

因此,IQueryable和之间的区别在于IEnumerable执行过滤器逻辑的位置。一个在客户端执行,另一个在数据库上执行。

因此,如果仅使用内存数据收集IEnumerable是一个不错的选择,但是如果要查询与数据库连接的数据收集,则IQueryable是一个更好的选择,因为它减少了网络流量并使用了SQL语言的强大功能。


嗨,非常感谢您的精彩解释。我了解为什么IQueryable是“内存不足”数据的更好选择,但我仍在努力理解IEnumerable为什么“内存不足”的数据更好?我仍然认为获取过滤的数据比获取数据并应用过滤器要好。
Imad

当它是“内存中”时,这并不重要。数据已经在内存中了,过滤的确切时间无关紧要。
罗尼·阿克塞拉德

@Imad例如,使用IQueryable或EntityFunctions不可能通过将实体DateTimeOffset转换为DateTime来投影数据。最好的方法是先将AsEnumerable()实体对象,然后将Select()放入包含DateTime的视图模型中。此过程使用内存功能。
Jeff Li

57

IEnumerable: IEnumerable最适合用于内存中的收集(或本地查询)。IEnumerable不会在项目之间移动,它是仅转发集合。

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

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


3
IEnumerable不使用延迟执行吗?
伊恩·沃伯顿

3
IEnumerable和IQueryable中都提供了延迟执行。另外有趣的信息可以在这里找到:stackoverflow.com/questions/2876616/...
伊格纳西奥Hagopian

18

简而言之,另一个主要区别是IEnumerable在服务器端执行select查询,在客户端加载内存中的数据,然后过滤数据,而IQueryable在服务器端使用所有过滤器执行select查询。


17

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

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

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

另外,如果您扩展查询范围:

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

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


10

IEnumerable引用了一个集合,但是IQueryable只是一个查询,它将在Expression Tree内部生成。我们将运行此查询以从数据库中获取数据。


8

以下提到的小测试可能有助于您了解IQueryable<T>和之间的差异IEnumerable<T>。我从这篇文章中转载了这个答案,当时我试图在其他人的文章中添加更正

我在DB(DDL脚本)中创建了以下结构:

CREATE TABLE [dbo].[Employee]([PersonId] [int] NOT NULL PRIMARY KEY,[Salary] [int] NOT NULL)

这是记录插入脚本(DML脚本):

INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(1, 20)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(2, 30)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(3, 40)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(4, 50)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(5, 60)
GO

现在,我的目标是仅从Employee数据库表中获取前2条记录。我将ADO.NET实体数据模型项添加到指向Employee数据库中表的控制台应用程序中,并开始编写LINQ查询。

可查询路线的代码

using (var efContext = new EfTestEntities())
{
    IQueryable<int> employees = from e in efContext.Employees  select e.Salary;
    employees = employees.Take(2);

    foreach (var item in employees)
    {
        Console.WriteLine(item);
    }
}

当我开始运行该程序时,我也已在SQL Server实例上启动了SQL Query Profiler的会话,这是执行摘要:

  1. 触发的查询总数:1
  2. 查询文字: SELECT TOP (2) [c].[Salary] AS [Salary] FROM [dbo].[Employee] AS [c]

只需IQueryable将这个Top (2)子句应用到数据库服务器端本身就足够聪明了,因此它通过网络仅带来了5条记录中的2条。客户端计算机端根本不需要任何进一步的内存中筛选。

IEnumerable路线的代码

using (var efContext = new EfTestEntities())
{
    IEnumerable<int> employees = from e in efContext.Employees  select e.Salary;
    employees = employees.Take(2);

    foreach (var item in employees)
    {
        Console.WriteLine(item);
    }
}

在这种情况下的执行摘要:

  1. 触发的查询总数:1
  2. 查询在SQL事件探查器中捕获的文本: SELECT [Extent1].[Salary] AS [Salary] FROM [dbo].[Employee] AS [Extent1]

现在,事物被IEnumerable带到Salary表中存在的所有5条记录,然后在客户端计算机上执行内存中筛选以获取前2条记录。因此,多余的数据(在这种情况下为3条附加记录)已通过导线传输。


7

这是我在类似帖子(关于此主题)上写的内容。(不,我通常不引述自己,但这是非常好的文章。)

“这篇文章很有帮助: LINQ-to-SQL中的IQueryable与IEnumerable

引用该文章,“根据MSDN文档,对IQueryable的调用是通过构建内部表达式树来进行的。“这些扩展IQueryable(Of T)的方法不会直接执行任何查询。相反,它们的功能是构建一个Expression对象,该对象是表示累积查询的表达式树。”

在C#和.NET平台上,表达式树是非常重要的构造。(它们通常很重要,但是C#使它们非常有用。)为了更好地理解它们之间的区别,建议您在此处阅读正式C#5.0规范中表达式语句 之间的区别对于分支到lambda演算的高级理论概念,表达式使支持将方法作为一等对象。IQueryable和IEnumerable之间的差异围绕这一点。IQueryable可以构建表达式树,而IEnumerable则不能,至少对于那些不在Microsoft秘密实验室工作的人来说,至少不是一般而言。

这是另一篇非常有用的文章,从推与拉的角度详细介绍了差异。(通过“推”与“拉”,我指的是数据流的方向。.NET和C#的响应式编程技术

这是一篇非常不错的文章,详细介绍了语句lambda和表达式lambda之间的区别,并更深入地讨论了表达式tress的概念:复习C#委托,表达式树和lambda语句与lambda表达式。”。


6

我们使用IEnumerableIQueryable操作从数据库检索的数据。IQueryable继承自IEnumerable,因此IQueryable包含所有IEnumerable功能。IQueryable和之间的主要区别IEnumerableIQueryable使用过滤器执行查询,而先IEnumerable执行查询,然后根据条件过滤数据。

在下面找到更多详细的区别:

IEnumerable

  1. IEnumerable存在于System.Collections命名空间中
  2. IEnumerable 在服务器端执行选择查询,在客户端加载内存中的数据,然后过滤数据
  3. IEnumerable 适合查询列表,数组等内存中的数据
  4. IEnumerable 有利于LINQ to Object和LINQ to XML查询

可查询

  1. IQueryable存在于System.Linq命名空间中
  2. IQueryable 使用所有过滤器在服务器端执行“选择查询”
  3. IQueryable 适用于查询内存外(例如远程数据库,服务)集合中的数据
  4. IQueryable 有利于LINQ to SQL查询

因此IEnumerable,通常用于处理内存中的集合,而IQueryable通常用于操纵集合。



2

如果我们要处理来自数据库的大量数据,则IQueryable比IEnumerable更快,因为IQueryable仅从数据库中获取必需的数据,而IEnumerable则从数据库中获取所有数据,而不管是否需要从数据库中获取数据


0

ienumerable:当我们要处理进程内存时,即没有数据连接时iqueryable:当要处理sql server,即数据连接时ilist:像添加对象,删除对象等操作

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.