当我们在序列上调用查询运算符时,会调用特定于序列的运算符
我的意思是如果我在Where<>()
上调用IEnumerable<>
运算符,将在Enumerable类中定义将被调用的运算符,如果在IQueryable<>
上调用它,将调用Queryable类中定义的运算符。 。
考虑在Enumerable类中定义的运算符Reverse
如果我想在Iqueryable<>
上调用它,那么我必须先使用AsEnumerable<>()
运算符将其转换为IEnumerable<>
。
db.Countries.OrderBy(cntry=>cntry.CountryName).AsEnumerable().Reverse()
但是Reverse运算符必须同时拥有所有记录,以便它可以反转它们 在上面的代码中,所有记录首先加载到内存中,然后Reverse()运算符正在反转它?
答案 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显式接口实现。