Why do Queue(T) and Stack(T) not implement ICollection(T)?

有些话、适合烂在心里 提交于 2019-12-02 18:22:20

I can't give the "what was the actual thinking" answer - perhaps one of the designers will give us the real thinkng and I can delete this.

However, putting myself in the mindset of "what if someone came to me to make this decision", I can think of an answer.. let me illustrate with this code:

public void SomeMethod<T>( ICollection<T> collection, T valueA, T valueB)
{

  collection.Add( valueA);
  collection.Add( valueB);

  if( someComplicatedCondition())
  {
    collection.Remove(valueA);
  }
}

(Sure, anyone can create a bad implementation of ICollection<T>, but we expect the framework to set the example). Let's assume Stack/Queue implement as you state in the question. So is the code above right, or does it have edge case bugs because ICollection<T>.Remove() should be checked? If valueA MUST be removed, how do I fix this to work with both Stack and Queue? There are answers, but obviously the code above is wrong in this case - even though it smells reasonable.

So both interpretations are valid, but I'm good with the decision made here - if I had the code above and knew I could be passed a Queue or Stack that I could design around it, but it sure would be an easy bug pit to fall into (everywhere you see ICollection<T>, remember the edge cases for remove!)

Ultimately perhaps they are just not ideal fits; if you want a list or collection - use a List<T> or Collection<T> ;p

Re Add - there is an implicit assumption that Add adds to the end of the collection, which is not true of a stack (although it is for a queue). In some ways, it actually confuses me that the enumerator for stack/queue does not dequeue/pop, since I largely expect items in a queue/stack to be fetched once each (and once only).

Maybe also (again, using my enumerator as just an example) people simply couldn't agree on exactly how it should behave in some of those scenarios, and lacking complete agreement, simply not implementing them was a better choice.

Philip has given a good answer (+1). There is another conceptual promise that Remove will break for Stack<T>. The ICollection<T>.Remove is documented as:

Removes the first occurrence of a specific object from the ICollection.

Stack<T> is LIFO, even if Remove was implemented, it will have to remove the last occurrence in case of duplicate objects.

If it doesnt make sense for Stack<T>, it's better avoidable for its equal and opposite cousin.


I would have liked it better if MS:

  • didn't document Remove for ICollection<T> like that. Deleting an equal object somewhere would have made more sense considering how vastly different the internal implementations of various structures are. Forcing the removal of first item looks like influenced from linear searching of simple structures like arrays.

  • had interfaces for queue structures. May be:

    public interface IPeekable<T> : IEnumerable<T> // or IInOut<T> or similar
    {
        int Count { get; }
    
        bool Contains(T item);
        T Peek();
        void Add(T item);
        bool Remove();
        void Clear();
    }
    
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!