Using IReadOnlyCollection instead of IEnumerabl

2019-02-16 15:16发布

问题:

My question is related to this one concerning the use of IEnumerable<T> vs IReadOnlyCollection<T>.

I too have always used IEnumerable<T> to expose collections as both return types and parameters because it benefits from being both immutable and lazily executed.

However, I am becoming increasingly concerned about the proliferation of places in my code where I must enumerate a parameter to avoid the possible multiple enumeration warning that ReSharper gives. I understand why ReSharper suggests this, and I agree with the code it suggests (below) in order to ensure encapsulation (i.e., no assumptions about the caller).

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

However, I find the repetitiveness of this code pollutive, and I agree with some sources that IReadOnlyCollection<T> is a better alternative, particularly the points made in this article, which states:

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.

However, as the observant may have noticed, this article only talks about using IReadOnlyCollection<T> for return types. My question is, would the same arguments equally apply to using it for parameters also? Any theoretical thoughts or comments on this would also be appreciated.

In fact, I'm thinking a general rule of thumb to use IReadOnlyCollection<T> would be where there would be possible multiple enumeration (vis-à-vis the ReSharper warning) if IEnumerable<T> is used. Otherwise, use IEnumerable<T>.

回答1:

Having thought about this further, I have come to the conclusion, based on the article I mentioned in my Question, that it is indeed OK to use IReadOnlyCollection<T> as a parameter, but only in functions where it will definitely be enumerated. If enumeration is conditional based on other parameters, object state, or workflow, then it should still be passed in as IEnumerable<T> so that lazy evaluation is semantically ensured.