为什么可能多次枚举 IE无数警告*不*显示



我有点困惑为什么Resharper(也不是Studio或FX Cop:(下面的代码中再次警告我IEnumerable的可能多次枚举:

//warning here fine
IEnumerable<IFileWrapper> filteredCollection = ctaWrappersContainer.FileContainer.Files.Where(x=>x.IsArchiveEntry);
int y1 = filteredCollection.Count();
int y2 = filteredCollection.Count();
//why no warning here?
int countOfIenumerable = ctaWrappersContainer.FileContainer.Files.Count();
int countOfIenumerableAgain = ctaWrappersContainer.FileContainer.Files.Count();

Files 集合是真正的 IEnumerable,它将在每次调用时重新评估。 下面介绍如何在代码中的某处分配 Files 属性:

container.Files = this.GetFilesFromArchive(container, zipFile.FullName, searchPattern);

GetFilesFromArchive()枚举条目并逐个返回它们(基于某些过滤器(。因此,每次我调用计数时,它都会再次执行此操作(如预期的那样(

protected override IEnumerable<IFileWrapper> GetFilesFromArchive(FileContainer fileContainer, string zipFilePath, string searchPattern)
{
//do some filtering magic on a collection of entries in a zip
yield return new ZipEntryWrapper(fileContainer, zipEntry, zipFile);
}

TL/DR:我同意@canton7的观点,这会导致太多误报。只是不要将昂贵的枚举对象放在属性中,这是一种不好的做法。

长版本:

无法判断枚举是否昂贵
基本上,对可能的多个枚举的检查试图警告您潜在的性能问题,因为IEnumerable通常来自昂贵的计算,如数据库查询。但是 ReSharper 无法确定枚举是否真的昂贵,因为跟踪所有可枚举项的来源将非常复杂且非常缓慢,在某些情况下是不可能的(可枚举来自类库中的接口或虚拟方法,并且重写可能在外部代码中(。

可枚举属性通常用于封装简单集合
这也适用于可枚举属性:ReSharper 无法确定该可枚举属性是否具有昂贵的枚举。如果它仍然继续并警告同一可枚举属性的多个枚举,则会导致太多误报,因为许多程序员不会在属性中放置昂贵的可枚举项。大多数情况下,可枚举属性在后台返回基本集合,如 List 或 HashSet,并选择返回类型IEnumerable来封装实现详细信息,并允许开发人员稍后将实现集合更改为其他集合。虽然现在我们有IReadOnlyCollection更适合这种封装,但我们仍然有大量带有IEnumerable的旧代码。

属性应该是轻量级的,不要把昂贵的计算放在那里
我会更进一步,认为即使 ReSharper 可以警告你对属性进行昂贵的多重枚举,属性返回昂贵的枚举仍然是一种不好的做法。即使您没有在此类属性上枚举两次的单个方法,您仍然可以拥有一个复杂的方法,该方法将连续多次调用不同的枚举方法。在这种情况下,您的团队成员甚至不会考虑缓存对枚举结果的访问,因为属性应该是轻量级的,几乎在每种情况下缓存它们都没有意义。

最新更新