IEnumerable和IQueryable混乱

时间:2014-04-15 20:21:37

标签: linq

此处的任何人都可以明确告诉我有关IEnumerableIQueryable以及某些示例帮助的不同之处?

谢谢

3 个答案:

答案 0 :(得分:4)

IEnumerable<>界面表示可以枚举某些内容 - 换句话说,您可以对其进行foreach循环。

IQueryable<>接口表示某些内容具有某种支持查询提供程序,它能够查看提供给它的表达式,并将它们转换为某种查询。

这些很容易让人感到困惑,部分原因是IQueryable<>扩展了IEnumerable<>,并且有一种名为.AsQueryable()的扩展方法可以导致任何IEnumerable<> (例如List<>转换为IQueryable<>

有多种扩展方法称为&#34; LINQ方法&#34;在Enumerable命名空间中的QueryableSystem.Linq类中。它们看起来几乎完全相同,并且它们的语法几乎相同,这进一步增加了您的困惑,但存在一些关键差异。 Enumerable类上的对象可以处理IEnumerable<>个对象,并且具有Func<>个签名。 Queryable课程中的IQueryable<>课程对Expression<Func<>>个对象有效,签名为Expression<Func<>>

令人困惑的是,C#语言会自动推断您是否尝试根据上下文创建Func<>var e = new[]{1,2,3,4,5}.AsEnumerable(); var q = e.AsQueryable(); var eStrings = e.Select(i => i.ToString()); var qStrings = q.Select(i => i.ToString()); ,因此使用情况完全相同在许多情况下也一样。例如:

Func<int, string> eSelect = i => i.ToString();
var eStrings = e.Select(eSelect);
Expression<Func<int, string>> qSelect = i => i.ToString();
var qStrings = q.Select(qSelect);

最后两行看起来是一样的,但他们实际上做的事情却截然不同。编译器正在为您有效地生成以下代码:

.ToList()

如果你对这些结果做了Func<>,那么第一个就会调用给定的Func<int, string> func = qSelect.Compile(); var s = func(1); // returns "1" ,它实际上是一个函数(你可以传递一个方法名而不是lambda表达式,例如),对于列表中的每个项目。第二个首先必须首先将表达式编译成函数,然后调用该编译的表达式。

IQueryable<>

这显然是更多的工作。那我们为什么要.ToList()?因为在某些情况下,知道某人想要做什么比实际运行他们给你的代码更重要。例如,如果您使用的是LINQ to Entities或LINQ to SQL等提供程序,那么运行var personIdStrings = Persons.Select(p => p.PersonId.ToString()).ToList(); 会导致此提供程序查看完整查询,其表达式保持不变,并认识到您想要的是数字并将它们变成字符串。所以像这样的查询:

SELECT CONVERT(NVarChar,[t0].[PersonId]) AS [value]
FROM [Person] AS [t0]

...实际上会导致生成一个SQL字符串,如下所示:

string

...然后将SQL发送到数据库,结果转换为一堆IQuerable<> s。这非常强大,允许您编写正常的C#代码,并将其解释为具有不同的含义,具体取决于提供商使{{1}}可供您使用。

答案 1 :(得分:1)

我相信,IQueryable用于数据库查询。您也无法在IQueryable中使用方法。

IEnumerable只是可以枚举的一些。就像列表或数组一样。

的IQueryable:

_repository.All<MyModel>(); // can return a IQueryable from the database.
例如,你不能在里面有一个方法,如果ID是GUID属性,你就不能这样做:

_repository.All<MyModel>(x => x.Id.ToString());

但是,IEnumerable是任何类型的List或Array,并且可以在其中使用方法。

来自MSDN的IQueryable

  

提供评估针对特定数据源的查询的功能,其中数据的类型是已知的。

来自MSDN的IEnumerable

  

公开一个枚举器,它支持对非泛型集合的简单迭代。

答案 2 :(得分:1)

这两者之间存在很大差异。实体框架使用 DbSet ,以便将linq的抽象暴露给数据库表。此曝光以 IQueryable 的形式出现。 IQueryable实现IEnumerable接口,并允许枚举查询结果到数据库。

  

枚举强制执行与IQueryable对象关联的表达式树   -MSDN:http://msdn.microsoft.com/en-us/library/vstudio/bb351562(v=vs.100).aspx

基本上IEnumerable只是对枚举所涉及的一组公开方法的引用。您可以在 MSDN: IEnumerable 中查看完整列表。

使用IQueryable对象通常意味着对活动数据库连接的引用。一旦处理了基础连接,任何尝试发出查询都将引发异常。因此,确保永远不会将IQueryable对象发送到视图或通过控制器非常重要。

可以使用.ToList()调用或.First().Single()等强制枚举,这会强制查询信息。