“可能多次枚举IEnumerable”问题?

时间:2014-04-28 08:13:48

标签: c#

我正在使用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;这里?如果确实有一个,这不是在这种情况下使用的最佳类型吗?

2 个答案:

答案 0 :(得分:5)

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

在这种情况下,我猜测它至少可以保证两次枚举。

警告存在是因为IEnumerable可以掩盖某些昂贵的内容,例如数据库调用(很可能是IQueryable),并且IEnumerable没有缓存作为其中一部分它的合同,它将重新列举新鲜的来源。这可能会导致以后的性能问题(我们已经被这种惊人的数量所困扰,我们甚至不使用IQueryable,我们的是在域模型遍历上。

尽管如此,它仍然只是一个警告,如果你知道多次调用可枚举的潜在慢源的潜在费用,那么你可以抑制它。

缓存结果的标准答案是ToListToArray

虽然我确实记得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不支持此重载。