AsEnumerable()是否缓存所有结果(LINQ)

时间:2010-05-24 06:28:30

标签: c# linq-to-sql

当我们在序列上调用查询运算符时,会调用特定于序列的运算符 我的意思是如果我在Where<>()上调用IEnumerable<>运算符,将在Enumerable类中定义将被调用的运算符,如果在IQueryable<>上调用它,将调用Queryable类中定义的运算符。 。

考虑在Enumerable类中定义的运算符Reverse 如果我想在Iqueryable<>上调用它,那么我必须先使用AsEnumerable<>()运算符将其转换为IEnumerable<>

db.Countries.OrderBy(cntry=>cntry.CountryName).AsEnumerable().Reverse()

但是Reverse运算符必须同时拥有所有记录,以便它可以反转它们 在上面的代码中,所有记录首先加载到内存中,然后Reverse()运算符正在反转它?

2 个答案:

答案 0 :(得分:4)

AsEnumerable除了更改表达式的编译时类型之外什么都不做。

它是这样实现的:

public static IEnumerable<T> AsEnumerable<T>(this IEnumerable<T> source)
{
    return source;
}

它甚至没有检查无效!

唯一的一点是更改编译时类型,强制使用Enumerable扩展方法而不是Queryable执行查询的其余部分。它就像一个演员阵容 - 除了演员在查询过程中经常会不方便,对于匿名类型,你无论如何都无法施放它。

因此,它实际上是关于查询的“源”在枚举时的作用。该源是否在返回任何结果之前将所有内容加载到内存中,还是将其流式传输? IIRC,LINQ to SQL实际上会将所有内容加载到内存中 - 但我可能错了。当然Reverse无论如何都要缓冲任何东西,但这并不意味着它会使用双倍的内存 - 在大多数情况下,这只意味着它会将引用缓冲到对象;它不会创建每个对象的新副本。

答案 1 :(得分:1)

IQueryable<T>扩展IEnumerable<T>,因此AsEnumerable是多余的。但是,如果你使用它,AsEnumerable不会贪婪加载集合(这将是一个非常烦人的“功能”)。显然,Reverse需要整个事情。 Mono使用List<T>和一个反向产生的简单迭代器生成器来实现Enumerable.Reverse

我相信AsEnumerable的唯一真正目的是强制使用IEnumerable显式接口实现。