【问题标题】:Resharper: Possible Multiple Enumeration of IEnumerableResharper:IEnumerable 的可能多重枚举
【发布时间】:2011-09-29 10:41:55
【问题描述】:

我正在使用新的 Resharper 6

我明白这意味着什么,并在适当的时候听取了建议,但在某些情况下,我不确定这是否真的很重要。

如下代码:

var properties = Context.ObjectStateManager.GetObjectStateEntry(this).GetModifiedProperties();
if (properties.Contains("Property1") || properties.Contains("Property2") || properties.Contains("Property3")) {
    ...
}

它在第二行每一次提到properties 都加了下划线,警告我正在多次枚举这个 IEnumerable。

如果我将 .ToList() 添加到第 1 行的末尾(将 properties 从 IEnumerable<string> 转换为 List<string>),警告就会消失。

但是可以肯定的是,如果我将其转换为 List,那么它将首先枚举整个 IEnumerable 以构建 List,然后根据需要枚举 List 以查找属性(即 1 个完整枚举,以及3个部分枚举)。而在我的原始代码中,它只进行了 3 个部分枚举。

我错了吗?这里最好的方法是什么?

【问题讨论】:

    标签: c# linq resharper ienumerable optimization


    【解决方案1】:

    如果您在 IEnumerable 上调用 Contains(),它将调用扩展方法,该方法将遍历项目以找到它。 IList 对 Contains() 有真正的实现,这可能比通过值的常规迭代更有效(它可能有一个带有哈希的搜索树?),因此它不会警告 IList。

    由于扩展方法只会知道它是IEnumerable,因此它可能无法使用Contains() 的任何内置方法,即使理论上可以识别已知类型并按顺序相应地转换它们使用它们。

    【讨论】:

      【解决方案2】:

      我不知道你的 properties 到底是什么 - 但如果它本质上代表一个未实现的数据库查询,那么你的 if 语句将执行三个查询。

      我怀疑这样做会更好:

      string[] propertiesToFind = { "Property1", "Property2", "Property3" };
      if (properties.Any(x => propertiesToFind.Contains(x))
      {
           ...
      }
      

      这将逻辑上只迭代序列一次 - 如果涉及数据库查询,它很可能只使用 SQL“IN”子句在数据库中完成所有操作一个查询。

      【讨论】:

      • 你确定它不会遍历属性并调用 Contains() 三次吗?这似乎在程序上是合乎逻辑的,但是我确实明白,如果它可以优化它以仅使用一次迭代,那将是更优化的。编辑:哎呀,对不起,我是反着读的……
      • @jishi:关键是现在包含在propertiesToFind 而不是properties 上完成
      • @jishi:在 lambda 表达式中只有一次对 Contains 的调用,所以每个元素只会调用一次 Contains ......但那是调用 Contains on 数组。如果评估序列很耗时(例如,它正在查看更大的序列并进行过滤),那么这将更有效。
      • SQL IN 子句只有在属性是 IQueryable 时才可能发生。
      猜你喜欢
      • 2014-06-13
      • 1970-01-01
      • 2012-01-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多