Reputation: 11338
I ended up in this post while searching for solutions to my problem - which led me to propose a new answer there - and - to be confronted with the following question:
Considering ICollection
implements IEnumerable
, and all linq extensions apply to both interfaces, is there any scenario where I would benefit from working with an IEnumerable
instead of an ICollection
?
The non generic IEnumerable
, for instance, does not provide a Count
extension.
Both ICollection
interfaces do.
Given all ICollection
, in any case, provide all functionality IEnumerable
implement - since it itself implements it - why then would I opt for IEnumerable
in place of ICollection
?
Backward compatibility with previous frameworks where ICollection
was not available ?
Upvotes: 3
Views: 1203
Reputation: 12184
I think there are actually two questions to answer here.
When would I want IEnumerable<T>
?
Unlike other collection types and the language in general, queries on IEnumerable
s are executed using lazy evaluation. That means you can potentially perform several related queries in only enumeration.
It's worth noting that lazy evaluation doesn't interact nicely with side effects because multiple enumeration could then give different results, you need to keep this in mind when using it. In a language like C#, lazy evaluation can be a very powerful tool but also a source of unexplained behaviour if you aren't careful.
When would I not want ICollection<T>
?
ICollection<T>
is a mutable interface, it exposes, amongst other things, add and remove methods. Unless you want external things to be mutating your object's contents, you don't want to be returning it. Likewise, you generally don't want to be passing it in as an argument for the same reason.
If you do want explicit mutability of the collection, by all means use ICollection<T>
.
Additionally, unlike IEnumerable<T>
or IReadOnlyCollection<T>
, ICollection<T>
is not covariant which reduces the flexibility of the type in certain use cases.
Non-generic versions
Things change a bit when it comes to the non-generic versions of these interfaces. In this case, the only real difference between the two is the lazy evaluation offered by IEnumerable
and the eager evaluation of ICollection
.
I personally would tend to avoid the non-generic versions due to the lack of type safety and poor performance from boxing/unboxing in the case of value types.
Summary
If you want lazy evaluation, use IEnumerable<T>
. For eager evaluation and immutability use IReadOnlyCollection<T>
. For explicit mutability use ICollection<T>.
Upvotes: 4
Reputation: 16070
IEnumerable
provides a read-only interface to a collection and ICollection
allows modification. Also IEnumerable
needs just to know how to iterate over elements. ICollection
has to provide more information.
This is semantically different. You don't always want to provide a functionality for modification of a collection.
There is a IReadOnlyCollection
but it doesn't implement ICollection
. This is a design of C#, that ReadOnly
is a different stripped down interface.
The point made by Tim is quite important. The internal working for Count
might be dramatically different. IEnumerable
does not need to know how many elements it spans over. Collection has a Property, so it has to know how many elements it contains. That is another crucial difference.
Upvotes: 4
Reputation: 2699
The idea is to use the simplest contract (interface) which fulfills the requirements: ICollection
is a collection, IEnumerable
is a sequence. A sequence could have deferred execution, it could be infinite, etc. The interface IEnumerable
just tells you that you can enumerate the sequence, that is all. This is different from ICollection
, which represents an actual collection containing a finite number of items.
As you can see, these are quite different. You cannot ignore the semantics of these contracts, and just focus on which interface inherits which other one.
If your algorithm only involves enumeration of the input data, then it should take an IEnumerable
. If you are, by contract, dealing with collections (i.e, you expect collections and nothing else), then you should use ICollection
.
Upvotes: 2