【问题标题】:"Possible multiple enumeration of IEnumerable" issue?“IEnumerable 的可能多重枚举”问题?
【发布时间】:2014-06-13 16:34:18
【问题描述】:

我正在使用 Resharper 获得一个 IEnumerable 的可能多重枚举,我正试图找出它是否真的是一个问题。这是我的方法:

public IEnumerable<Contact> GetContacts(IContactManager contactManager, string query)
{
    IEnumerable<Contact> contacts = contactManager.GetContacts(query);
    if (contacts.Any()) return contacts; // Get the warning on this line
    // Do some other stuff
    return new[] {
        new Contact { Name = "Example" }
    }
}

应该很明显,但我正在搜索Contact,如果搜索未返回任何结果,我将返回一组默认值。消费者应该只收到一个可以枚举而不是修改的列表。

这里的“多重枚举”在哪里?如果确实有一个,这不是在这种情况下使用的最佳类型吗?

【问题讨论】:

    标签: c#


    【解决方案1】:

    多重枚举潜力是您调用Any,这将导致第一次枚举,然后是潜在由该方法的调用者进行的第二次枚举。

    在这种情况下,我猜大多数情况下可以保证至少会发生两次枚举。

    警告存在是因为IEnumerable 可以伪装一些昂贵的东西,例如数据库调用(很可能是IQueryable),并且由于IEnumerable 没有缓存作为其合同的一部分,它会重新枚举源头新鲜。这可能会在以后导致性能问题(我们已经被这个惊人的数量所困扰,我们甚至不使用IQueryable,我们使用的是域模型遍历)。

    也就是说,它仍然只是一个警告,如果您意识到多次调用一个可枚举的潜在慢源的潜在费用,那么您可以抑制它。

    缓存结果的标准答案是ToList 或ToArray。

    虽然我确实记得曾经在内部缓存过一个IRepeatable 版本的IEnumerable。这在我的免费代码库的深处丢失了:-)

    【讨论】:

      【解决方案2】:

      Enumerable.Any 执行查询以检查序列是否包含元素。如果没有元素,您可以使用 DefaultIfEmpty 提供不同的默认值:

      public IEnumerable<Contact> GetContacts(IContactManager contactManager, string query)
      {
          IEnumerable<Contact> contacts = contactManager.GetContacts(query)
              .DefaultIfEmpty(new Contact { Name = "Example" });
          return contacts;
      }
      

      请注意,LINQ-To-SQL 不支持此重载。

      【讨论】:

      • 我想这不会摆脱警告。您错过了//Do some other stuff 部分,大概会枚举集合并导致警告!。
      • @SriramSakthivel:我假设 "do some other stuff" 只是他提供默认/备用数组的部分,如果查询没有产生应该返回的数组结果。但是,忽略此警告可能是最好的选择,因为 OP 的方法应该没问题。
      • 抱歉,@TimSchmelter 是正确的。 // Do some other stuff 只是填充后备数组
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-29
      • 2011-10-09
      相关资源
      最近更新 更多