为什么可能会多次枚举IEnumerable警告*未显示*

时间:2019-12-02 11:20:21

标签: c# resharper ienumerable

我有点困惑为什么 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);
        }

1 个答案:

答案 0 :(得分:1)

TL / DR :我同意@ canton7 ,它将导致过多的误报。只是不要在属性中添加昂贵的枚举,这是一个不好的做法。

长版:

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

可枚举的属性通常用于封装简单的集合
这也适用于枚举属性:ReSharper无法确定该枚举是否具有昂贵的枚举。如果仍然继续进行并警告同一可枚举属性的多个枚举,则将导致过多的误报,因为许多程序员没有在属性中放置昂贵的枚举。通常,可枚举的属性在后台返回诸如List或HashSet之类的基本集合,并且选择返回类型IEnumerable来封装实现细节,并允许开发人员稍后将实现集合更改为其他内容。尽管现在我们有了IReadOnlyCollection,它对于这种封装更好,但仍然有大量的旧代码带有IEnumerable

属性本来就是轻量级的,请不要在其中进行昂贵的计算
我会进一步争论,即使ReSharper可以警告您有关属性的昂贵的多重枚举,对于属性返回昂贵的可枚举的属性仍然是一个坏习惯。即使没有单个方法可以对此类属性进行两次枚举,您仍然可以使用复杂的方法来连续多次调用不同的枚举方法。在这种情况下,您的队友甚至不会考虑缓存对枚举结果的访问,因为属性本​​来是轻量级的,并且几乎在每种情况下都没有缓存它们的意义。

相关问题