Resharper:IEnumerable 可能存在多次枚举

38

我正在使用新的Resharper版本6。 我的代码中的一些地方已经被下划线标记,并警告我可能会有一个可能的IEnumerable多个枚举

我理解这意味着什么,并在适当的情况下采纳了建议,但是在某些情况下,我不确定它是否真的很重要。

就像下面的代码:

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

在第二行中,它会用下划线标出每个properties的提及,并警告我正在多次枚举此IEnumerable

如果我在第一行末尾添加.ToList()(将propertiesIEnumerable<string>转换为List<string>),则警告消失了。

但是,如果我将其转换为列表,则首先需要枚举整个IEnumerable以构建列表,然后根据需要枚举列表来查找属性(即完全枚举一次和3次部分枚举)。而在我的原始代码中,它只执行3次部分枚举。

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

2个回答

42

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

猜想最好这样做:

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

这将逻辑上只迭代一次序列——如果涉及到数据库查询,它很可能能够使用SQL的“IN”子句在单个查询中全部完成。


你确定这样不会遍历属性并三次调用Contains()吗?从程序逻辑上看似乎是这样,但我理解如果能够优化为只使用一次迭代将更加优化。编辑:啊,抱歉,我反过来读了... - jishi
@jishi:关键是现在在propertiesToFind上执行Contains操作,而不是properties - sehe
@jishi:在 lambda 表达式中只有一次对 Contains 的调用,因此它每个元素只会调用一次 Contains... 但是这是在数组上调用 Contains。如果计算序列需要时间(例如,它正在查看一个更大的序列并进行过滤),那么这将更有效率。 - Jon Skeet
SQL中的IN子句只有在properties为IQueryable时才可能发生。 - Hans

8
如果在IEnumerable上调用Contains(),它将调用扩展方法,该方法只是按顺序迭代项目以查找它。IList对Contains()有真正的实现,这些实现可能比常规迭代值更有效(它可能具有哈希搜索树?),因此它不会警告使用IList。由于扩展方法仅知道它是IEnumerable,因此即使在理论上可以识别已知类型并相应地进行强制转换以利用它们,它也可能无法利用Contains()的任何内置方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接