.net 为什么队列(T)和堆栈(T)不实现ICollection(T)?

.net 为什么队列(T)和堆栈(T)不实现ICollection(T)?,.net,interface,stack,queue,icollection,.net,Interface,Stack,Queue,Icollection,在我提问之前,让我先给出一个明显的答案:ICollection接口包括一个Remove方法来删除任意元素,而Queue和Stack实际上不支持该方法(因为它们只能删除“end”元素) 好吧,我意识到了。实际上,我的问题不是关于队列或堆栈集合类型的;相反,它是关于不为本质上是T值集合的任何泛型类型实现ICollection的设计决策 我觉得奇怪的是。假设我有一个接受任意T集合的方法,为了编写代码,了解集合的大小会很有用。例如(下面的代码很简单,仅用于说明!): 完全放弃ICollection接口不

在我提问之前,让我先给出一个明显的答案:
ICollection
接口包括一个
Remove
方法来删除任意元素,而
Queue
Stack
实际上不支持该方法(因为它们只能删除“end”元素)

好吧,我意识到了。实际上,我的问题不是关于
队列
堆栈
集合类型的;相反,它是关于不为本质上是
T
值集合的任何泛型类型实现
ICollection
的设计决策

我觉得奇怪的是。假设我有一个接受任意
T
集合的方法,为了编写代码,了解集合的大小会很有用。例如(下面的代码很简单,仅用于说明!):

完全放弃
ICollection
接口不是更有意义吗(当然,我不是说放弃实现,因为这将是一个突破性的改变;我只是说,停止使用它),只需为没有完美匹配的成员显式实现
ICollection

我的意思是,看看
ICollection
提供了什么:

  • 计数
    --
    队列
    堆栈
    都有此功能
  • IsReadOnly
    --
    队列
    堆栈
    很容易就能做到这一点
  • Add
    -
    Queue
    可以明确地实现这一点(使用
    Enqueue
    ),也可以使用
    Stack
    (使用
    Push
  • 清除
    ——检查
  • 包含
    ——检查
  • CopyTo
    ——检查
  • GetEnumerator
    ——检查(duh)
  • Remove
    ——这是唯一一个
    Queue
    Stack
    没有完美匹配的
真正的问题是:
ICollection.Remove
返回一个
bool
;因此,
Queue
的显式实现可以完全(例如)检查要删除的项目是否实际上是head元素(使用
Peek
),如果是,则调用
Dequeue
并返回
true
,否则返回
false
<代码>堆栈可以很容易地通过
Peek
Pop
得到类似的实现

好了,既然我已经写了大约一千字来解释为什么我认为这是可能的,我提出了一个显而易见的问题:为什么
队列
堆栈
的设计者没有实现这个接口?也就是说,设计因素是什么(我可能没有考虑到)这导致了一个决定,这将是一个错误的选择?为什么要改为实施
ICollection

我想知道,在设计我自己的类型时,有什么指导原则,我应该考虑的接口实现,我可能忽略这个问题。例如,显式实现通常不完全支持的接口是否被认为是一种不好的做法(如果是这样,这似乎与实现IList有冲突,例如,
List
)?队列/堆栈的概念与
ICollection
的含义之间是否存在概念上的脱节

基本上,我感觉到一定有一个很好的理由
Queue
(例如)不实现
ICollection
,我不想盲目地设计自己的类型,以不适当的方式实现接口,而不知道自己在做什么,也不想完全思考自己在做什么


对于这个超长的问题,我深表歉意。

说到底,也许它们不是理想的搭配;如果您想要列表或集合-请使用
列表
集合
;p

Re
Add
-有一个隐含的假设,即
Add
会添加到集合的末尾,这对于堆栈来说是不正确的(尽管它是针对队列的)。在某种程度上,堆栈/队列的枚举器不退出队列/pop实际上让我感到困惑,因为我基本上希望队列/堆栈中的项目每次提取一次(并且只提取一次)

也可能(再次,以我的枚举器为例)人们根本无法就在某些情况下它应该如何表现达成一致,如果没有完全一致,干脆不实施它们是更好的选择。

我无法给出“实际想法是什么”答案-也许其中一位设计师会给我们真正的想法,我可以删除这个

然而,把自己放在“如果有人来找我做这个决定怎么办”的心态中,我可以想出一个答案。。让我用这段代码来说明:

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

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

  if( someComplicatedCondition())
  {
    collection.Remove(valueA);
  }
}
public void somethod(ICollection集合、T值A、T值B)
{
收款。增加(价值a);
收款。增加(增值b);
if(somecompleddcondition())
{
收集。移除(valueA);
}
}
(当然,任何人都可以创建一个糟糕的
ICollection
实现,但我们希望框架能够树立榜样)。让我们假设堆栈/队列实现如您在问题中所述。那么,是右上方的代码,还是因为应该选中
ICollection.Remove()
,所以它有边缘大小写错误?如果必须删除
valueA
,如何解决此问题以同时使用堆栈和队列?答案是有的,但显然,在这种情况下,上面的代码是错误的——尽管它闻起来很合理

因此,这两种解释都是有效的,但我对这里所做的决定很满意——如果我有上面的代码,并且知道我可以被传递一个队列或堆栈,我可以围绕它进行设计,但这肯定是一个很容易陷入的bug坑(无论你在哪里看到
ICollection
,记住边缘cas)
// OK, so to accommodate those bastard Queue<T> and Stack<T> types,
// we will just accept any IEnumerable<T>...
static IEnumerable<T> FirstHalf<T>(this IEnumerable<T> source)
{
    int count = CountQuickly<T>(source);
    /* ... */
}

// Then, assuming we've got a collection type with a Count property,
// we'll use that...
static int CountQuickly<T>(IEnumerable collection)
{
    // Note: I realize this is basically what Enumerable.Count already does
    // (minus the exception); I am just including it for clarity.
    var genericColl = collection as ICollection<T>;
    if (genericColl != null)
    {
        return genericColl.Count;
    }

    var nonGenericColl = collection as ICollection;
    if (nonGenericColl != null)
    {
        return nonGenericColl.Count;
    }

    // ...or else we'll just throw an exception, since this collection
    // can't be counted quickly.
    throw new ArgumentException("Cannot count this collection quickly!");
}
public void SomeMethod<T>( ICollection<T> collection, T valueA, T valueB)
{

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

  if( someComplicatedCondition())
  {
    collection.Remove(valueA);
  }
}
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();
}