8

I am going to write a library to traverse an object graph (like some kind of serialization).
You will need to judge if an object is a collection in the traverse, so the ICollection came out of my mind. (string has also implemented IEnumerable)

But it is really weird that almost all containers in Collections have implemented ICollection except HashSet only implemented ICollection<T>...

I have checked out almost all common containers in System.Collections namespace:

ArrayList : IList, ICollection, IEnumerable, ICloneable  
BitArray : ICollection, IEnumerable, ICloneable  
Hashtable : IDictionary, ICollection, IEnumerable, ISerializable, IDeserializationCallback, ICloneable  
Queue : ICollection, IEnumerable, ICloneable  
SortedList : IDictionary, ICollection, IEnumerable, ICloneable  
Stack : ICollection, IEnumerable, ICloneable  
Dictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IDictionary, ICollection, IReadOnlyDictionary<TKey, TValue>, IReadOnlyCollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable, ISerializable, IDeserializationCallback
HashSet<T> : ISerializable, IDeserializationCallback, ISet<T>, ICollection<T>, IEnumerable<T>, IEnumerable  
LinkedList<T> : ICollection<T>, IEnumerable<T>, ICollection, IEnumerable, ISerializable, IDeserializationCallback  
List<T> : IList<T>, ICollection<T>, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable  
Queue<T> : IEnumerable<T>, ICollection, IEnumerable  
SortedDictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IDictionary, ICollection, IEnumerable  
SortedList<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IDictionary, ICollection, IEnumerable  
SortedSet<T> : ISet<T>, ICollection<T>, IEnumerable<T>, ICollection, IEnumerable, ISerializable, IDeserializationCallback  
Stack<T> : IEnumerable<T>, ICollection, IEnumerable  

Is this a bug? Or there are some reason behind?

user247702
  • 23,641
  • 15
  • 110
  • 157
Mr. Ree
  • 871
  • 9
  • 20
  • 2
    I believe [this link](https://stackoverflow.com/questions/2353346/why-doesnt-icollectiont-implement-icollection) is relevant to your question. – Saragis Jul 07 '15 at 15:33
  • 2
    The .NET collection hierarchy is really messed up. – usr Jul 07 '15 at 15:33
  • 3
    If you are upgrading 1.1 code to 2.0 the fact that `List` implements `ICollection` arguably helps you replace old uses of `ArrayList` (arguably it would be nicer to just have compiler errors pointing to where you need to upgrade to `ICollection`). There isn't a non-generic version of `HashSet` prior to it being introduced with 3.5, so one reason for supporting `ICollection` with the most of the others isn't there. – Jon Hanna Jul 07 '15 at 15:42
  • 1
    @JonHanna But `SortedSet<>` is an even newer type, and it does implement non-generic `ICollection`? – Jeppe Stig Nielsen Jul 07 '15 at 15:44
  • 1
    Corresponding meta post: http://meta.stackoverflow.com/questions/293815/is-it-subjective-to-ask-about-why-something-wasnt-implemented-in-the-language – Binkan Salaryman Jul 07 '15 at 15:47
  • 1
    @JeppeStigNielsen Yep, but you could argue that it shouldn't. For that matter you could argue that `List` shouldn't either, but you'd have a stronger case with `HashSet` and `SortedSet`. It's design decisions so it's more about what you can argue as a clue to what someone did argue than immutable laws of nature. – Jon Hanna Jul 07 '15 at 15:47

1 Answers1

0

ICollection isn't anywhere near as useful now as it was with .NET 1.1 when there was no ICollection<T> offering greater type safety. There's very little one can usefully do with ICollection that one can't do with ICollection<T>, often with greater efficiency and/or type safety, especially if one writes generic methods for those cases where one might want to do something with collections of different element types.

This though begs the question of why the likes of List<T> did implement ICollection. But when List<T> was introduced with .NET 2.0 all legacy code was using ICollection and ArrayList, not ICollection<T> and List<T>. Upgrading code to use List<T> rather than ArrayList can be a pain, especially if it means having to either immediately change all uses of ICollection it would hit to use ICollection<T> or, even worse, double up because a method was being hit with the List<T> that was also being hit with other non-generic collections and so versions of the method would be needed for each. Implementing ICollection eased the upgrade path by allowing people to be more piecemeal in how they took advantage of generic collections.

When HashSet<T> came out generics had been in use for three years already, and there was not a previous non-generic hash-set type provided by the framework, so there was less of an upgrade pain, and hence less of a motivation for supporting ICollection.

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
  • 1
    ICollection is very useful for determining that object is finite non-lazy collection. Most people just use IEnumerable to determine that object is some kind of collection but IEnumerable can be lazy and/or infinite. So ICollection is smallest interface that almost all finite non-lazy collections support. And it is very annoying that few collections like HashSet, ImmutableQueue, ImmutableStack does not. – Yuri Bondarchuk Sep 17 '21 at 10:04