Enumerable.Any() 和可能的多重枚举

And*_*kov 3 c#

Rider/ReSharper 给了我可能的多重枚举警告:

public void ProcessProductCodes(IEnumerable<string> productCodes) {
    if (productCodes.Any()) {
        DoStuff(productCodes);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是误报,还是 Any() 函数确实搞乱了集合的枚举?

Tao*_*Gil 5

IEnumerable接口表示可以迭代的项目序列,但不对序列的起源做出任何假设。例如,它可能是数据库查询。如果是这种情况,您将在这里对数据库进行 2 次调用,一次用于检查序列中是否有任何项目,另一次将它们传递给函数DoStuff,这显然不是最佳性能,并且 ReSharper 发出警告你关于这件事。

为了避免此问题,您有两种不同的选择。如果项目集合已在内存中,您可以通过将函数的签名更改为:

public void ProcessProductCodes(ICollection<string> productCodes) { ... }
Run Code Online (Sandbox Code Playgroud)

如果您不能保证这一点,您可以在函数的开头执行.ToList()or操作:.ToArray

public void ProcessProductCodes(IEnumerable<string> productCodes) {
  var productCodesList = productCodes.ToList();
  if (productCodesList .Any()) {
      DoStuff(productCodesList );
  }
Run Code Online (Sandbox Code Playgroud)

ReSharper 会为您完成此操作,只需选择快速重构(通常使用Alt+Enter)。

  • 如果您先“查看”然后“进行真正的枚举”,那么您将执行两次枚举,这就是“IEnumerable”的工作原理。不要将“IEnumerable”视为项目的集合,而是将其视为“获取集合项目的指令”。每次访问它们时,即使您只想要第一个,您也将执行获取它们的操作(可能会执行昂贵的操作,例如数据库调用)。 (2认同)