2010-07-16 66 views
3

我们知道你不能添加一个额外的条款一样.Where().First()为编译查询,因为这改变了查询,并强制进行重新编译。我想知道哪些方法可以用来“关闭”已编译的查询。哪些方法来关闭编译的查询

我知道大多数人使用.AsEnumerable().ToList(),但哪些其他方法也适用?我可以使用.AsQueryable(),还是这是一个没有操作?

哪个更好的性能?我知道.AsEnumerable().ToList()快,但如果我想的IQueryable,是.AsEnumerable().AsQueryable().ToList()更好?

+3

“.AsEnumerable()比.ToList()更快...并且苹果不是梨。 – spender 2010-07-16 08:51:58

+0

是的,我知道你通常会选择你所需要的。不过,我认为了解性能差异很重要。 – Carvellis 2010-07-16 09:03:21

回答

7

在大多数情况下,AsEnumerable().AsQueryable()可能是你想要什么,因为:

  • 这样做的明确AsEnumerable(),你没有运行的底层实现使AsQueryable()成无操作的风险,从而破坏您尝试关闭查询。我并不是说现在的EF使得AsQueryable()是一个无操作(据我所知,事实并非如此),只是没有记录行为 - 无论是无操作还是透明地调用AsEnumerable() - 都没有记录所以依靠它是不安全的。
  • AsEnumerable(),不像ToList(),不加载你的整个结果在存储器中,以便查询。对于大型结果集来说,这很重要。理论上可能的是,对于较小的结果集,使用ToList()可能会有一些优势(例如,优化的ToList()实现从底层提供者抽取大块数据,而枚举涉及更多上下文切换),但这似乎不太可能,依赖于提供者和版本,而AsEnumerable()的大结果集优势将永远存在。

的一个情况下我不喜欢打电话ToList()是,当我明确地确实要强制查询现在执行。例如,如果我想在一个方法的早些​​时候捕获查询中的错误,以便稍后可以简化错误处理,或者我想在继续查询的其余部分之前验证所有基础数​​据。或者如果查询更容易在两个切碎时进行测试。我永远不会这样做,除非我知道我的记录集将会很小,因为在数百万行查询中调用ToList()会杀死你的RAM。

要回答在MSDN细节LINQ方法力查询执行的LINQ文档中您的其他问题,Converting Data Types。根据该页面,ToArray()ToDictionary(),ToList()ToLookup()都强制执行查询。

AsEnumerable(),相比之下,不强制立即执行查询,但“关闭”查询(这里使用的术语,不知道是否有一个为官一任此)。每http://msdn.microsoft.com/en-us/library/bb335435.aspx

的AsEnumerable方法可以 被用来隐藏自定义方法和 反而让标准查询 运营商提供。

换句话说,运行AsEnumerable将迫使像Take()Where()所有呼叫使用通用LINQ的实现,而不是anythign定制,这将导致重新编译。

+0

谢谢,这完美地回答了我的问题。 – Carvellis 2010-07-26 08:27:31

1

哪些方法可用于“关闭”已编译的查询。

返回序列的方法使用延迟执行,除非该方法类似于ToXYZWhereSelectTake,Skip,GroupByOrderBy等等。返回查询的单个对象执行力,像FirstSingleToListToArrayToDictionaryToLookupAnyAll等方法更看到这个优秀的线程:Linq - What is the quickest way to find out deferred execution or not?

我知道大多数人请使用。 AsEnumerable()或.ToList(),但哪些其他方法也适用?我可以使用.AsQueryable(),还是这是一个无操作?

它们都是不同的。贾斯汀有一个盛大的解释。您可能还想看到:What's the difference(s) between .ToList(), .AsEnumerable(), AsQueryable()?这有一个很好的答案。


通常,您可以通过查看方法本身的名称来理解方法的语义。名为AsSomething的方法意味着它什么都不做,但将输入返回为。这可能涉及也可能不涉及返回一个新的对象,但参考被以某种方式维护。例如,一个List<T>.AsEnumerable()只是投射到IEnumerable<T>(当然它在linq上下文中有更大的含义)。您可以将它重新投射到List<T>,并将其变为无处不在。为了测试它:

var list = new List<int> { 1, 2 }; 
var enum = list.AsEnumerable(); 
var newlist = enum as List<string>; 
newlist.Add(3); 
//print enum.Count() -> 3 

虽然看起来像ToSomething方法,你会得到一个完全新的对象往往转化成别的东西。

var list = new List<int> { 1, 2 }; 
var newlist = list.ToList(); 
newlist.Add(3); 
//print list.Count -> 2 

让我们考虑一下linq上下文之外的东西。 object.ToString()导致新的字符串表示(字符串无论如何都是不可变的,所以这有点无意义)。一个有趣的语义是List<T>.AsReadonly,它返回一个新的ReadOnlyCollection<T>实例,但是在它外面改变列表也会改变内部列表ReadOnlyCollection<T>,因此命名为AsReadonly

var list = new List<int> { 1, 2 }; 
var readonlylist = list.AsReadonly(); 
list.Add(3); 
//print readonlylist.Count -> 3