3

正如我们所知,您不能将额外的子句添加.Where().First()已编译的查询中,因为这会更改查询并强制重新编译。我想知道的是哪些方法可用于“关闭”已编译的查询。

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

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

4

2 回答 2

7

在大多数情况下,AsEnumerable().AsQueryable()这可能是您想要的,因为:

  • 通过执行显式AsEnumerable(),您不会冒底层实现AsQueryable()变成无操作的风险,从而破坏您关闭查询的尝试。我并不是说今天的 EF 进行AsQueryable()了无操作(据我所知,它没有),只是没有记录行为——无论是无操作还是透明地调用 AsEnumerable()——依赖它是不安全的。
  • AsEnumerable()与 不同ToList(),不会将整个结果集加载到内存中以进行查询。这对于大型结果集很重要。从理论上讲,对于较小的结果集,使用 ToList() 可能会有一些优势(例如,优化的 ToList() 实现从底层提供者中提取大块数据,而枚举涉及更多的上下文切换)但这似乎不太可能而且很难依赖于不同的提供者和版本,而 AsEnumerable() 的大结果集优势将永远存在。

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

要回答您的其他问题, MSDN 上的 LINQ 文档中的转换数据类型详细说明了哪些 LINQ 方法强制执行查询。根据该页面,ToArray()ToDictionary()ToList()ToLookup()所有强制查询执行。

相比之下, AsEnumerable() 不会强制立即执行查询,但会“关闭”查询(在此处使用您的术语,不确定是否有官方术语)。根据http://msdn.microsoft.com/en-us/library/bb335435.aspx

AsEnumerable 方法可用于隐藏自定义方法,而是使标准查询运算符可用。

换句话说,运行 AsEnumerable 将强制所有调用Take()Where()使用通用 LINQ 实现,而不是任何会导致重新编译的自定义。

于 2010-07-26T06:05:35.440 回答
1

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

返回序列的方法使用延迟执行,除非该方法类似于ToXYZ. Where, Select, Take, Skip,GroupBy等等OrderBy都属于这个。返回单个对象的方法会强制执行查询,例如First,和Single, , ,等。有关更多信息,请参阅这个出色的线程:Linq - 找出延迟执行的最快方法是什么?ToListToArrayToDictionaryToLookupAnyAll

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

他们都是不同的。贾斯汀有一个宏大的解释。您可能还想看看:.ToList()、.AsEnumerable()、AsQueryable() 之间有什么区别?这有一个很好的答案。


一般来说,你可以通过查看方法本身的名称来理解方法的语义。一个名为的方法AsSomething意味着它什么都不做,只是将输入作为 something返回。这可能涉及也可能不涉及返回一个新对象,但是以某种方式维护了一个引用。例如, aList<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
于 2013-11-11T13:12:40.110 回答