IQueryable,List,IEnumerator之间的区别?
我想知道什么是IQueryable,列表,IEnumerator和什么时候我应该使用每一个不同?
例如,当使用LINQ到SQL我会做这样的事情
public List<User> GetUsers() { return db.User.where(/* some query here */).ToList(); } 现在我想知道是否应该使用IQueryable,但我不确定在列表中使用它的优点。
  IQueryable<T>旨在允许查询提供程序(例如,LINQ to SQL或entity framework之类的ORM)使用查询中包含的expression式将请求转换为另一种格式。 换句话说,LINQ-to-SQL会查看您正在使用的实体的属性以及您正在进行的比较,并实际创build一个SQL语句来expression(希望)等效的请求。 
  IEnumerable<T>比IQueryable<T>更通用(尽pipeIQueryable<T>所有实例都实现IEnumerable<T> ),并且只定义了一个序列。 但是, Enumerable类中有扩展方法可用于定义该接口上的某些查询types运算符,并使用普通代码来评估这些条件。 
  List<T>只是一个输出格式,它实现了IEnumerable<T> ,与查询没有直接关系。 
 换句话说,当你使用IQueryable<T> ,你正在定义和expression的东西被翻译成别的东西。 即使您正在编写代码,该代码也不会被执行 ,只会被检查并转化为其他内容,如实际的SQL查询。 正因为如此,这些expression式中只有某些东西是有效的。 例如,你不能调用你在这些expression式中定义的普通函数,因为LINQ-to-SQL不知道如何把你的调用转换成SQL语句。 大部分这些限制只在运行时才被评估,不幸的是。 
 当您使用IEnumerable<T>进行查询时,您正在使用LINQ-to-Objects,这意味着您正在编写用于评估查询或转换结果的实际代码,所以通常没有任何限制你可以做什么。 您可以自由地从这些expression式中调用其他函数。 
用LINQ to SQL
 要与上述区别结合起来,牢记在实践中这是如何实现的也是很重要的。 当您在LINQ to SQL中针对数据上下文类编写查询时,它会生成一个IQueryable<T> 。 无论你对IQueryable<T>本身做什么,都将变成SQL,所以你的过滤和转换将在服务器上完成。 无论你如何处理IEnumerable<T> ,都将在应用程序级完成。 有时这是可取的(例如在需要使用客户端代码的情况下),但在很多情况下这是无意的。 
 例如,如果我有一个表示Customer表的Customers属性的上下文,并且每个客户都有一个CustomerId列,那么让我们来看看执行此查询的两种方法: 
 var query = (from c in db.Customers where c.CustomerId == 5 select c).First(); 
 这将产生SQL查询数据库的CustomerId等于5的Customerlogging。就像: 
 select CustomerId, FirstName, LastName from Customer where CustomerId = 5 
 现在,如果通过使用AsEnumerable()扩展方法将Customers转换为IEnumerable<Customer>会发生什么? 
 var query = (from c in db.Customers.AsEnumerable() where c.CustomerId == 5 select c).First(); 
 这个简单的改变有一个严重的后果。 因为我们把Customers变成一个IEnumerable<Customer> ,这将把整个表格带回来,并在客户端进行过滤(严格来说,这将带回表中的每一行, 直到遇到一个符合关键字的行 ,但重点是相同的)。 
ToList()
 直到现在,我们只讨论了IQueryable和IEnumerable 。 这是因为他们是相似的,免费的接口。 在这两种情况下,你都在定义一个查询 ; 也就是说,您正在定义在哪里查找数据,要应用哪些filter以及要返回哪些数据。 这两个都是查询 
 query = from c in db.Customers where c.CustomerId == 5 select c; query = from c in db.Customers.AsEnumerable() where c.CustomerId == 5 select c; 
 就像我们已经谈到的那样,第一个查询使用IQueryable ,第二个使用IEnumerable 。 不过,在这两种情况下,这只是一个查询 。 定义查询实际上不会对数据源做任何事情。 查询实际上是在代码开始遍历列表时执行的。 这可以发生多种方式; 一个foreach循环,调用ToList()等 
 查询首先执行, 每次迭代。 如果您要在query上调用ToList()两次,则最终会得到两个具有完全不同对象的列表。 他们可能包含相同的数据,但他们将是不同的参考。 
在评论之后编辑
 我只想清楚什么时候客户端和服务器端完成之间的区别。 如果您将IQueryable<T>作为IEnumerable<T>引用,则仅在IEnumerable<T> 之后完成的查询将在客户端完成。 例如,说我有这个表和一个LINQ到SQL的上下文: 
 Customer ----------- CustomerId FirstName LastName 
 我首先构造一个基于FirstName的查询。 这将创build一个IQueryable<Customer> : 
 var query = from c in db.Customers where c.FirstName.StartsWith("Ad") select c; 
 现在我将该查询传递给一个带有IEnumerable<Customer>的函数,并根据LastName一些筛选: 
 public void DoStuff(IEnumerable<Customer> customers) { foreach(var cust in from c in customers where c.LastName.StartsWith("Ro")) { Console.WriteLine(cust.CustomerId); } } 
 我们在这里完成了第二个查询,但是它正在IEnumerable<Customer> 。 这里将发生什么事情是第一个查询将被评估,运行这个SQL: 
 select CustomerId, FirstName, LastName from Customer where FirstName like 'Ad%' 
 所以我们要带回所有FirstName以"Ad"开头的人。 请注意,这里没有关于LastName 。 那是因为它被客户端过滤掉了。 
 一旦它带回这些结果,程序将迭代结果并仅传递LastName以"Ro"开头的logging。 这样做的缺点是我们带回了数据,也就是所有的LastName 不是以"Ro"开始的行 – 可能已经被服务器过滤了。 
  IQueryable<T> :抽象数据库访问,支持查询的懒惰评估 
  List<T> :条目的集合。 懒惰的评价不支持 
  IEnumerator<T> :提供迭代和IEnumerable<T> ( IQueryable<T>和List<T>都是)的能力, 
 该代码的问题非常简单 – 它总是在调用时执行查询。 如果你要返回db.User.Where(...)而不是(这是一个IQueryable<T> ),你可以持续对查询进行评估,直到实际需要(迭代)为止。 另外,如果该方法的用户需要指定更多的谓词,那么这些谓词也将在数据库中执行,这使得它更快。 
 当你需要某个实体的强types集合时,使用iList或List<item> 。 
 当你想把哑数据作为一个对象集合来使用Iqueryable和Ienumurator时,它将作为一个松散的types集合返回,并且没有任何限制。 
 我宁愿使用List<type>因为使用列表包装并强制types集合我的结果集。 
此外,使用列表将使您能够添加,sorting并将图层转换为Array,Ienumurator或Queryable。