使用IReadOnlyCollection 而不是IEnumerable 来获取参数,以避免可能的多次枚举

我的问题与关于使用IEnumerable vs IReadOnlyCollection

我也总是使用IEnumerable将集合作为返回类型和参数公开,因为它既可以是不可变的又是懒惰的执行。

但是,我越来越关注我的代码中的地方的扩散,我必须枚举一个参数,以避免ReSharper给出的可能的多个枚举警告。 我理解为什么ReSharper建议这一点,我同意它建议的代码(下面)以确保封装(即,没有关于调用者的假设)。

  Foo[] arr = col as Foo[] ?? col.ToArray(); 

但是,我发现此代码的重复性是污染性的,并且我同意一些消息来源IReadOnlyCollection是一个更好的选择,特别是本文中提出的观点,其中指出:

最近,我一直在考虑返回IEnumerable的优点和缺点。

从好的方面来说,它与接口得到的一样小,所以它让你作为方法作者更灵活,而不是像IList或( 天堂禁止 )一个更重的替代方案。

但是,正如我在上一篇文章中所概述的那样, IEnumerable返回会诱使调用者违反Liskov替换原则 。 他们很容易使用像Last()Count()这样的LINQ扩展方法,其语义IEnumerable不承诺。

我们需要的是一种更好的方法来锁定一个返回的集合,而不会让这样的诱惑如此突出。 (我想起Barney Fife艰难地学习这一课。)

输入IReadOnlyCollection ,.NET 4.5中的新增function。 它只向IEnumerable添加一个属性: Count属性。 通过承诺计数,你向你的呼叫者保证你的IEnumerable确实有一个终点。 然后他们可以清楚地使用像Last()这样的LINQ扩展方法。

但是,正如观察者可能已经注意到的那样,本文仅讨论如何将IReadOnlyCollection用于返回类型。 我的问题是,相同的论点同样适用于将其用于参数吗? 对此的任何理论思考或评论也将受到赞赏。

事实上,我正在考虑使用IReadOnlyCollection的一般经验法则是,如果使用IEnumerable可能会有多次枚举(相对于ReSharper警告)。 否则,使用IEnumerable

在进一步考虑之后,我得出结论,根据我在我的问题中提到的文章,确实可以使用IReadOnlyCollection作为参数,但仅限于肯定会枚举它的函数。 如果枚举是基于其他参数,对象状态或工作流的条件,则它仍应作为IEnumerable传递,以便在语义上确保延迟评估。