我正在使用新的Resharper版本6.在我的代码中的几个地方,它强调了一些文本,并警告我可能存在可能多次枚举IEnumerable 。
我理解这意味着什么,并在适当的时候采纳了建议,但在某些情况下我不确定这实际上是一个大问题。
如下面的代码所示:
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次部分枚举。
我错了吗?这里最好的方法是什么?
答案 0 :(得分:41)
我不确切知道你的properties
到底在哪里 - 但如果它实际上代表了一个非物质化的数据库查询,那么你的if
语句将执行三个查询。
我怀疑最好这样做:
string[] propertiesToFind = { "Property1", "Property2", "Property3" };
if (properties.Any(x => propertiesToFind.Contains(x))
{
...
}
逻辑只会迭代序列一次 - 如果涉及数据库查询,它可能只能使用SQL“IN”子句在数据库中完成所有操作一个查询。
答案 1 :(得分:6)
如果在IEnumerable上调用Contains()
,它将调用扩展方法,该方法将遍历项目以便找到它。 IList
具有Contains()
的实际实现,它可能比通过值的常规迭代更有效(它可能有一个带有哈希的搜索树?),因此它不会与IList
发出警告
由于扩展方法只知道它是IEnumerable
,它可能无法利用Contains()
的任何内置方法,即使理论上可以识别已知类型和强制转换因此,为了利用它们。