对参数使用 IReadOnlyCollection<T> 而不是 IEnumerable<T> 以避免可能的多重枚举
Using IReadOnlyCollection<T> instead of IEnumerable<T> for parameters to avoid possible multiple enumeration
我的问题与 this one 有关 IEnumerable<T>
与 IReadOnlyCollection<T>
的使用有关。
我也一直使用 IEnumerable<T>
将集合公开为 return 类型和参数,因为它受益于不可变和延迟执行。
但是,我越来越担心我的代码中必须枚举参数以避免 ReSharper 可能给出的多重枚举警告的位置的激增。我理解为什么 ReSharper 建议这样做,并且我同意它建议的代码(如下)以确保封装(即,没有关于调用者的假设)。
Foo[] arr = col as Foo[] ?? col.ToArray();
但是,我发现此代码的重复性具有污染性,并且我同意一些消息来源认为 IReadOnlyCollection<T>
是更好的选择,尤其是 this article 中提出的观点:
Lately, I’ve been considering the merits and demerits of returning
IEnumerable<T>
.
On the plus side, it is about as minimal as an interface gets, so it
leaves you as method author more flexibility than committing to a
heavier alternative like IList<T>
or (heaven forbid) an array.
However, as I outlined in the last post, an IEnumerable<T>
return
entices callers to violate the Liskov Substitution Principle. It’s too
easy for them to use LINQ extension methods like Last()
and Count()
,
whose semantics IEnumerable<T>
does not promise.
What’s needed is a better way to lock down a returned collection
without making such temptations so prominent. (I am reminded of Barney
Fife learning this lesson the hard way.)
Enter IReadOnlyCollection<T>
, new in .NET 4.5. It adds just one
property to IEnumerable<T>
: the Count
property. By promising a count,
you assure your callers that your IEnumerable<T>
really does have a
terminus. They can then use LINQ extension methods like Last()
with a
clear conscience.
然而,细心的人可能已经注意到,本文只讨论了将 IReadOnlyCollection<T>
用于 return 类型。我的问题是,同样的论点是否同样适用于将它用于参数?任何对此的理论想法或评论也将不胜感激。
事实上,我认为使用 IReadOnlyCollection<T>
的一般经验法则是如果 IEnumerable<T>
是可能的多重枚举(相对于 ReSharper 警告)用过的。否则,使用 IEnumerable<T>
.
进一步考虑后,根据我在问题中提到的文章,我得出结论,使用 IReadOnlyCollection<T>
作为参数确实可以,但只能在它所在的函数中使用肯定会被列举。如果枚举是基于其他参数、对象状态或工作流的条件,那么它仍应作为 IEnumerable<T>
传递,以便在语义上确保惰性评估。
我的问题与 this one 有关 IEnumerable<T>
与 IReadOnlyCollection<T>
的使用有关。
我也一直使用 IEnumerable<T>
将集合公开为 return 类型和参数,因为它受益于不可变和延迟执行。
但是,我越来越担心我的代码中必须枚举参数以避免 ReSharper 可能给出的多重枚举警告的位置的激增。我理解为什么 ReSharper 建议这样做,并且我同意它建议的代码(如下)以确保封装(即,没有关于调用者的假设)。
Foo[] arr = col as Foo[] ?? col.ToArray();
但是,我发现此代码的重复性具有污染性,并且我同意一些消息来源认为 IReadOnlyCollection<T>
是更好的选择,尤其是 this article 中提出的观点:
Lately, I’ve been considering the merits and demerits of returning
IEnumerable<T>
.On the plus side, it is about as minimal as an interface gets, so it leaves you as method author more flexibility than committing to a heavier alternative like
IList<T>
or (heaven forbid) an array.However, as I outlined in the last post, an
IEnumerable<T>
return entices callers to violate the Liskov Substitution Principle. It’s too easy for them to use LINQ extension methods likeLast()
andCount()
, whose semanticsIEnumerable<T>
does not promise.What’s needed is a better way to lock down a returned collection without making such temptations so prominent. (I am reminded of Barney Fife learning this lesson the hard way.)
Enter
IReadOnlyCollection<T>
, new in .NET 4.5. It adds just one property toIEnumerable<T>
: theCount
property. By promising a count, you assure your callers that yourIEnumerable<T>
really does have a terminus. They can then use LINQ extension methods likeLast()
with a clear conscience.
然而,细心的人可能已经注意到,本文只讨论了将 IReadOnlyCollection<T>
用于 return 类型。我的问题是,同样的论点是否同样适用于将它用于参数?任何对此的理论想法或评论也将不胜感激。
事实上,我认为使用 IReadOnlyCollection<T>
的一般经验法则是如果 IEnumerable<T>
是可能的多重枚举(相对于 ReSharper 警告)用过的。否则,使用 IEnumerable<T>
.
进一步考虑后,根据我在问题中提到的文章,我得出结论,使用 IReadOnlyCollection<T>
作为参数确实可以,但只能在它所在的函数中使用肯定会被列举。如果枚举是基于其他参数、对象状态或工作流的条件,那么它仍应作为 IEnumerable<T>
传递,以便在语义上确保惰性评估。