IEnumerable<T>
implements IEnumerable
.
But ICollection<T>
does not implement ICollection
.
What was the rationale for this and/or was it just an oversight?
IEnumerable<T>
implements IEnumerable
.
But ICollection<T>
does not implement ICollection
.
What was the rationale for this and/or was it just an oversight?
As Nick said, ICollection
is pretty much useless.
These interfaces are similar only by their name, CopyTo
and Count
are the only properties in common. Add
, Remove
, Clear
, Contains
and IsReadOnly
have been added while IsSychronized
and SyncRoot
have been removed.
In essence, ICollection<T>
is mutable, ICollection
is not.
Krzysztof Cwalina has more on this topic
ICollection<T>
seems likeICollection
, but it’s actually a very different abstraction. We found thatICollection
was not very useful. At the same time, we did not have an abstraction that represented an read/write non-indexed collection.ICollection<T>
is such abstraction and you could say thatICollection
does not have an exact corresponding peer in the generic world;IEnumerable<T>
is the closest.
ICollection<T>
and ICollection
are actually very different interfaces that unfortunately share a name and not much else.
ICollection<T>
seems likeICollection
, but it’s actually a very different abstraction. We found thatICollection
was not very useful. At the same time, we did not have an abstraction that represented an read/write non-indexed collection.ICollection<T>
is such abstraction and you could say thatICollection
does not have an exact corresponding peer in the generic world;IEnumerable<T>
is the closest.
First, IList<T>
does not implement IList
either, probably for the same reasons. IList<T>
implements: ICollection<T>, IEnumerable<T>, IEnumerable
Some parts of ICollection just aren't necessary, but changing an interface after it's out in the wild is breaking at best.
Look at ICollection:
public interface ICollection : IEnumerable
{
void CopyTo(Array array, int index);
int Count { get; }
bool IsSynchronized { get; }
object SyncRoot { get; }
}
It's just not properties you need in most cases, when I want a Collection I've never once needed this, nor would want to implement it. It got old would be the reasoning I suppose, but you'd have to ask the .Net team for the affirmative answer.
Both ICollection
and ICollection<T>
contain at least one method that returns the collection type (GetEnumerator
) and another that takes it as an argument (CopyTo
).
ICollection<T>.GetEnumerator
is covariant with ICollection.GetEnumerator
, because T
is a more specific type than System.Object
. This part is OK. This is why IEnumerable<T>
is able to subclass (and thus be substitutable) for IEnumerable
.
But if we want ICollection<T>
to be substitutable for ICollection
, we also need ICollection<T>.CopyTo
to be contravariant with ICollection.CopyTo
, which it is not. The ICollection<T>.CopyTo
method cannot accept a parameter of a less-specific type than T
(the generics grammar constrains it to be T
or smaller). And if ICollection<T>.CopyTo
method is not contravariant in its argument, then that means the ICollection<T>
interface as a whole is not substitutable for ICollection
.
That might be a little hard to make sense of; it's more complicated because it deals with arrays. It's blindingly obvious in IList<T>
, where implementing both interfaces could potentially break the type safety that's supposed to be guaranteed by generics (by simply invoking the non-generic IList.Add
method). But that's actually just another way of saying that the IList<T>.Add
method is not contravariant in its arguments with IList.Add
- the generic method cannot accept the less-specific type System.Object
as an argument.
Long story short: ICollection<T>
simply can't be made substitutable for ICollection
under all circumstances, and therefore cannot inherit from it.