31

找出哪些 .net 框架 linq 方法(例如 .IEnumerable linq 方法)使用延迟执行与哪些不使用延迟执行实现的最快方法是什么。

在多次编码时,我想知道这是否会以正确的方式执行。找出答案的唯一方法是转到 MSDN 文档以确保。是否有任何更快的方法、任何目录、网络上的任何列表、任何备忘单、任何其他可以分享的技巧?如果是,请这样做。这将帮助许多 linq 新手(比如我)少犯错误。唯一的另一种选择是检查文档,直到有人使用它们足以记住(这对我来说很难,我倾向于不记得记录在某处并且可以查找的“任何东西”:D)。

4

6 回答 6

38

通常返回序列的方法使用延迟执行:

IEnumerable<X> ---> Select ---> IEnumerable<Y>

并且返回单个对象的方法不会:

IEnumerable<X> ---> First ---> Y

因此,像Where, Select, Take,Skip和这样的方法使用延迟执行是因为它们可以,而像, ,GroupBy和这样的方法因为不能而不能。OrderByFirstSingleToListToArray

还有两种类型的延迟执行。例如,该Select方法在被要求生成一个项目时一次只会获取一个项目,而OrderBy当被要求返回第一个项目时,该方法将不得不消耗整个源。因此,如果您OrderBy在 a 之后链接 a Select,则执行将推迟到您获得第一个项目,但随后OrderBy将询问Select所有项目。

于 2010-10-08T21:46:47.860 回答
8

我使用的指南:

  • 始终假设任何返回IEnumerable<T>IQueryable<T>可以并且可能会使用延迟执行的 API。如果您正在使用这样的 API,并且需要多次遍历结果(例如获取 Count),则在这样做之前转换为集合(通常通过调用 .ToList() 扩展方法。

  • 如果您要公开枚举,请始终将其公开为集合(ICollection<T>IList<T>),如果这是您的客户通常使用的。例如,数据访问层通常会返回域对象的集合。仅IEnumerable<T>当延迟执行对于您要公开的 API 来说是一个合理的选项时才公开。

于 2010-10-08T22:54:49.137 回答
5

实际上,还有更多;此外,您需要考虑缓冲与非缓冲。OrderBy 可以延迟,但迭代时必须消耗整个流。

通常,LINQ 中返回 IEnumerable 的任何内容都会被延迟 - 而 Min 等(返回值)不会被延迟。通常可以推断缓冲(与不缓冲),但坦率地说,反射器是一种非常快速的确定方法。但请注意,这通常是一个实现细节。

于 2010-10-08T21:49:07.510 回答
2

对于实际的“延迟执行”,您需要适用于 IQueryable 的方法。基于 IQueryable 的方法链用于构建表示您的查询的表达式树。只有当您调用采用 IQueryable 并产生具体或 IEnumerable 结果的方法(ToList() 和类似的、AsEnumerable() 等)时,Linq 提供程序才会评估树(Linq2Objects 内置于框架中,Linq2SQL 和现在是 MSEF;其他 ORM 和持久层框架也提供 Linq 提供程序)和返回的实际结果。框架中的任何 IEnumerable 类都可以使用 AsQueryable() 扩展方法强制转换为 IQueryable,并且将转换表达式树的 Linq 提供程序(如 ORM)将提供 AsQueryable() 作为 linq 查询的起点他们的数据。

即使针对 IEnumerable,一些 Linq 方法也是“懒惰的”。因为 IEnumerable 的美妙之处在于您不必了解所有内容,只需了解当前元素以及是否存在其他元素,作用于 IEnumerable 的 Linq 方法通常会返回一个迭代器类,该迭代器类会在任何时候从其源中吐出一个对象链中后面的方法要求一个。任何不需要了解整个集合的操作都可以被懒惰地评估(Select 和 Where 是两个大的;还有其他的)。确实需要了解整个集合(通过 OrderBy 排序、使用 GroupBy 分组以及 Min 和 Max 等聚合)的那些将把它们的整个源可枚举到 List 或 Array 中并对其进行处理,从而强制通过所有更高节点对所有元素进行评估。一般来说,

于 2010-10-08T21:50:57.383 回答
2

以下是您可以知道您的查询是否会被推迟的不同方法的摘要:

  1. 如果您使用查询表达式语法而不是查询方法语法,那么它将被延迟。

  2. 如果您使用的是查询方法语法,它可能会根据它返回的内容而被推迟。

  3. 将鼠标悬停在var关键字上(如果这是您用作用于存储查询的变量的类型)。如果它说,IEnumerable<T>那么它将被推迟。

  4. 尝试使用 foreach 遍历查询。如果你得到一个错误,说它不能迭代你的变量,因为它不支持GetEnumerator(),你知道查询没有被延迟。

资料来源:基本 Linq

于 2019-01-25T01:00:49.503 回答
1

如果使用 .AsQueryable() 将集合转换为 IQueryable,则 LINQ 调用将使用延迟执行。

请参阅此处:将 IQueryable 与 Linq 一起使用

于 2010-10-08T21:45:58.617 回答