IQueryable<T>
和IEnumerable<T>
有什么区别?
另请参阅与此问题重叠的What's the difference between IQueryable and IEnumerable。
首先,IQueryable<T>
扩展了IEnumerable<T>
界面,所以你可以用“普通”IEnumerable<T>
做任何事情,你也可以用IQueryable<T>
。
IEnumerable<T>
只有一个GetEnumerator()
方法返回一个Enumerator<T>
,你可以调用它的MoveNext()
方法迭代T序列。
IQueryable<T>
具有IEnumerable<T>
不具备的两个属性 - 一个指向查询提供程序(例如,LINQ to SQL提供程序),另一个指向将IQueryable<T>
对象表示为运行时可遍历的抽象语法树的查询表达式可以由给定的查询提供程序理解(大多数情况下,您不能在没有抛出异常的情况下将LINQ to SQL表达式提供给LINQ to Entities提供程序)。
表达式可以简单地是对象本身的常量表达式,也可以是组合的查询运算符和操作数集的更复杂的树。调用查询提供程序的IQueryProvider.Execute()
或IQueryProvider.CreateQuery()
方法,并将表达式传递给它,然后分别返回查询结果或另一个IQueryable
。
IEnumerable和IQueryable都用于保存数据集合并执行数据操作操作,例如过滤数据集合。在这里,您可以找到与示例的最佳差异比较。 Revisiting C# delegates, expression trees, and lambda statements vs. lambda expressions. http://www.gurujipoint.com/2017/05/difference-between-ienumerable-and.html
我们使用和IEnumerable
来操作从数据库中检索的数据。 IQueryable
继承自IEnumerable
,所以IQueryable
确实包含所有IQueryable
功能。 IEnumerable
和IQueryable
之间的主要区别在于IEnumerable
使用过滤器执行查询,而IQueryable
首先执行查询,然后根据条件过滤数据。
在下面找到更详细的区别:
IEnumerable的
IEnumerable
存在于IEnumerable
命名空间中System.Collections
在服务器端执行select查询,在客户端加载内存中的数据,然后过滤数据IEnumerable
适用于查询内存集合(如List,Array)中的数据IEnumerable
有利于LINQ to Object和LINQ to XML查询IQueryable的
IEnumerable
存在于IQueryable
命名空间中System.Linq
在服务器端使用所有过滤器执行“选择查询”IQueryable
适用于从外部存储器(如远程数据库,服务)集合中查询数据IQueryable
有利于LINQ to SQL查询所以IQueryable
通常用于处理内存中的集合,而IEnumerable
通常用于操作集合。
如果我们处理来自数据库的大量数据,IQueryable比IEnumerable更快,因为IQueryable只从数据库中获取所需的数据,因为IEnumerable可以获取所有数据,无论数据库是否有必要
ienumerable:当我们要处理进程内存时,即没有dataconnection iqueryable:何时处理sql server,即与数据连接ilist:如添加对象,删除对象等操作
主要区别在于IQueryable<T>
的LINQ运算符采用Expression
对象而不是委托,这意味着它接收的自定义查询逻辑(例如谓词或值选择器)采用表达式树的形式而不是方法的委托。
IEnumerable<T>
非常适合处理在内存中迭代的序列,但是IQueryable<T>
允许诸如数据库或Web服务之类的远程数据源之类的内存不足。更多内容:
这是一个很好的Reactive Programming for .NET and C# Developers - An Introduction To IEnumerable
, IQueryable
, IObservable
, and IQbservable
,它展示了这些界面的不同之处,值得一看。
下面是一个很长的描述性答案。
要记住的第一个要点是video on youtube接口继承自IQueryable
,所以无论IEnumerable
能做什么,IEnumerable
也可以。
有许多不同之处,但让我们讨论一下产生最大差异的一大差异。当您使用IQueryable
或Entity框架加载集合时,IEnumerable
接口非常有用,并且您希望对集合应用过滤器。
考虑下面使用LINQ
和实体框架的简单代码。它使用IEnumerable
过滤器来获取Where
为EmpId
的记录。
2
这是在EmpEntities ent = new EmpEntities();
IEnumerable<Employee> emp = ent.Employees;
IEnumerable<Employee> temp = emp.Where(x => x.Empid == 2).ToList<Employee>();
代码所在的客户端执行过滤器的地方。换句话说,所有数据都是从数据库中获取的,然后在客户端进行扫描并获取IEnumerable
的记录是EmpId
。
但现在看到下面的代码我们已经将2
改为IEnumerable
。它在服务器端创建一个SQL查询,只将必要的数据发送到客户端。
IQueryable
所以EmpEntities ent = new EmpEntities();
IQueryable<Employee> emp = ent.Employees;
IQueryable<Employee> temp = emp.Where(x => x.Empid == 2).ToList<Employee>();
和IQueryable
之间的区别在于过滤器逻辑的执行位置。一个在客户端执行,另一个在数据库上执行。
因此,如果您只处理内存中的数据收集,那么IEnumerable
是一个不错的选择,但如果您想查询与数据库连接的数据集合,那么IQueryable是一个更好的选择,因为它可以减少网络流量并使用SQL语言的强大功能。
IEnumerable:IEnumerable最适合处理内存中的集合(或本地查询)。 IEnumerable不会在项目之间移动,它只是前向收集。
IQueryable:IQueryable最适合远程数据源,如数据库或Web服务(或远程查询)。 IQueryable是一个非常强大的功能,可以实现各种有趣的延迟执行方案(如分页和基于组合的查询)。
因此,当您必须简单地遍历内存中的集合时,使用IEnumerable,如果您需要对数据集和其他数据源等集合进行任何操作,请使用IQueryable
简单来说,其他主要区别在于IEnumerable在服务器端执行select查询,在客户端加载内存中的数据,然后在IQueryable上使用所有过滤器在服务器端执行select查询时过滤数据。
在现实生活中,如果您使用的是LINQ-to-SQL之类的ORM
在这两种情况下,如果你不调用IEnumerable
或ToList()
,那么每次使用它时都会执行查询,所以,比方说,你有一个ToArray()
并从中填充4个列表框,然后查询将针对数据库运行4次。
此外,如果您扩展您的查询:
IQueryable<T>
然后使用IQueryable生成的SQL将包含“where name =”a“,但是有了IEnumerable,将从数据库中撤回更多的角色,然后x.name =”a“检查将由.NET完成。
IEnumerable引用了一个集合,但IQueryable只是一个查询,它将在Expression Tree中生成。我们将运行此查询以从数据库中获取数据。
下面提到的小测试可能会帮助您理解q.Where(x.name = "a").ToList()
和IQueryable<T>
之间差异的一个方面。我从IEnumerable<T>
帖子中复制了这个答案,我试图在其他人的帖子中添加更正
我在DB(DDL脚本)中创建了以下结构:
this
这是记录插入脚本(DML脚本):
CREATE TABLE [dbo].[Employee]([PersonId] [int] NOT NULL PRIMARY KEY,[Salary] [int] NOT NULL)
现在,我的目标是简单地从数据库中的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
表中获取前2条记录。我在我的控制台应用程序中添加了一个ADO.NET实体数据模型项,指向我数据库中的Employee
表,并开始编写LINQ查询。
IQueryable路线的代码:
Employee
当我开始运行这个程序时,我还在我的SQL Server实例上启动了一个SQL Query profiler会话,这里是执行摘要:
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);
}
}
只是SELECT TOP (2) [c].[Salary] AS [Salary] FROM [dbo].[Employee] AS [c]
足够聪明,可以在数据库服务器端本身应用IQueryable
子句,因此它只能通过线路传输5条记录中的2条。客户端计算机端根本不需要任何进一步的内存中过滤。
IEnumerable路线的代码:
Top (2)
在这种情况下执行摘要:
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);
}
}
现在问题是SELECT [Extent1].[Salary] AS [Salary]
FROM [dbo].[Employee] AS [Extent1]
带来了IEnumerable
表中存在的所有5条记录,然后在客户端计算机上执行了内存过滤以获得前2条记录。因此,不必要地通过线路传输更多数据(在这种情况下为3个附加记录)。
这是我在类似帖子上写的(关于这个主题)。 (不,我通常不引用自己,但这些都是非常好的文章。)
“这篇文章很有帮助:Salary
。
引用该文章,“根据MSDN文档,对IQueryable进行的调用通过构建内部表达式树来进行操作。 “这些扩展IQueryable(Of T)的方法不会直接执行任何查询。相反,它们的功能是构建一个Expression对象,它是一个表示累积查询的表达式树。”
表达式树是C#和.NET平台上非常重要的构造。 (它们一般很重要,但C#使它们非常有用。)为了更好地理解差异,我建议阅读表达式和语句之间的差异IQueryable vs IEnumerable in LINQ-to-SQL对于分支为lambda演算的高级理论概念,表达式首先支持方法 - 类对象。 IQueryable和IEnumerable之间的区别在于这一点。 IQueryable构建了表达式树,而IEnumerable则没有,至少对于我们这些不在微软秘密实验室工作的人来说,这一点并非一般。
这是另一篇非常有用的文章,详细介绍了推送与拉动视角的差异。 (通过“推”与“拉”,我指的是数据流的方向.in the official C# 5.0 specification here.
这是一篇非常好的文章,详细介绍了语句lambdas和表达式lambdas之间的区别,并更深入地讨论了表达式tress的概念:Reactive Programming Techniques for .NET and C#。“