我正在使用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
,如果搜索没有返回结果,我会返回默认值数组。消费者应该只收到一个可以枚举但不能修改的列表。
&#34;多重枚举&#34;这里?如果确实有一个,这不是在这种情况下使用的最佳类型吗?
答案 0 :(得分:5)
多个枚举可能性是您调用Any
,这将导致第一次枚举,然后由该方法的调用者进行潜在的第二次枚举。
在这种情况下,我猜测它至少可以保证两次枚举。
警告存在是因为IEnumerable
可以掩盖某些昂贵的内容,例如数据库调用(很可能是IQueryable
),并且IEnumerable
没有缓存作为其中一部分它的合同,它将重新列举新鲜的来源。这可能会导致以后的性能问题(我们已经被这种惊人的数量所困扰,我们甚至不使用IQueryable
,我们的是在域模型遍历上。
尽管如此,它仍然只是一个警告,如果你知道多次调用可枚举的潜在慢源的潜在费用,那么你可以抑制它。
缓存结果的标准答案是ToList
或ToArray
。
虽然我确实记得IRepeatable
版本的IEnumerable
版本的{{1}}一旦内部缓存了它。这在我的免费代码库的深处丢失了: - )
答案 1 :(得分:3)
Enumerable.Any
执行查询以检查sequnce是否包含元素。如果没有元素,您可以使用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不支持此重载。