对参数使用 IReadOnlyCollection<T> 而不是 IEnumerable<T> 以避免可能的多次枚举
Posted
技术标签:
【中文标题】对参数使用 IReadOnlyCollection<T> 而不是 IEnumerable<T> 以避免可能的多次枚举【英文标题】:Using IReadOnlyCollection<T> instead of IEnumerable<T> for parameters to avoid possible multiple enumeration 【发布时间】:2017-05-06 23:07:02 【问题描述】:我的问题与this one 有关IEnumerable<T>
与IReadOnlyCollection<T>
的使用有关。
我也一直使用IEnumerable<T>
将集合公开为返回类型和参数,因为它受益于不可变和延迟执行。
但是,我越来越担心我的代码中必须枚举参数以避免 ReSharper 给出的可能的多重枚举警告的地方的扩散。我理解为什么 ReSharper 建议这样做,并且我同意它建议的代码(如下)以确保封装(即,不对调用者进行任何假设)。
Foo[] arr = col as Foo[] ?? col.ToArray();
但是,我发现此代码的重复性具有污染性,并且我同意一些消息来源,即 IReadOnlyCollection<T>
是更好的选择,尤其是在 this article 中提出的观点,其中指出:
最近一直在考虑回国的利弊
IEnumerable<T>
.从好的方面来说,它几乎是一个界面所获得的最小限度,所以它 让您作为方法作者比承诺更灵活 较重的替代方案,例如
IList<T>
或 (heaven forbid) 数组。但是,正如我在 the last post 中概述的那样,
IEnumerable<T>
返回 引诱来电者违反Liskov Substitution Principle。它太 他们很容易使用Last()
和Count()
等LINQ扩展方法, 其语义IEnumerable<T>
不承诺。需要一种更好的方法来锁定返回的集合 没有使这种诱惑如此突出。 (我想起了巴尼 法夫艰难地学习了这一课。)
输入
IReadOnlyCollection<T>
,.NET 4.5 中的新功能。它只增加了一个IEnumerable<T>
的属性:Count
属性。通过承诺计数, 您向来电者保证您的IEnumerable<T>
确实有 终点站。然后他们可以使用 LINQ 扩展方法,例如Last()
无愧于心。
但是,细心的人可能已经注意到,本文只讨论了使用IReadOnlyCollection<T>
来表示返回类型。我的问题是,相同的论点是否同样适用于将其用于参数?对此的任何理论思想或方法也将不胜感激。
事实上,如果使用IEnumerable<T>
,我认为使用IReadOnlyCollection<T>
的一般经验法则是可能存在多个枚举(相对于ReSharper 警告)。否则,使用IEnumerable<T>
。
【问题讨论】:
resharper 的注释中有一个名为[NoEnumeration]
的属性,它只是一个属性,但那里说 Indicates that IEnumerable, passed as parameter, is not enumerated.
它什么也没做,但我用它是因为它很酷
@M.kazemAkhgary,这很酷,而且很有用,我猜你没有枚举IEnumerable
。但我的问题比那个用例更广泛,更多的是关于 IEnumerable
枚举的位置。在这些情况下,IReadOnlyCollection<T>
是更好的选择吗,出于我提到的原因(即文章中提出的观点)?
【参考方案1】:
进一步思考后,根据我在问题中提到的文章得出结论,使用IReadOnlyCollection<T>
作为参数确实可以,但仅限于肯定会被枚举的函数.如果枚举是基于其他参数、对象状态或工作流的条件,那么它仍应作为IEnumerable<T>
传入,以便在语义上确保惰性求值。
【讨论】:
以上是关于对参数使用 IReadOnlyCollection<T> 而不是 IEnumerable<T> 以避免可能的多次枚举的主要内容,如果未能解决你的问题,请参考以下文章
不变性/只读语义(特别是 C# IReadOnlyCollection<T>)
IReadOnlyCollection 上的隐式/显式转换混淆
为啥泛型 ICollection 不在 .NET 4.5 中实现 IReadOnlyCollection?
有没有办法将 IReadOnlyCollection<T>/IReadOnlyList<T> 与 protobuf-net 一起使用