我创建了一个自定义的通用队列,实现了一个通用的IQueue接口,该接口使用了System.Collections.Generic命名空间中的通用队列作为私有内部队列。示例已清除无关代码。
public interface IQueue<TQueueItem>
{
void Enqueue(TQueueItem queueItem);
TQueueItem Dequeue();
}
public class CustomQueue<TQueueItem> : IQueue<TQueueItem>
{
private readonly Queue<TQueueItem> queue = new Queue<TQueueItem>();
...
public void Enqueue(TQueueItem queueItem)
{
...
queue.Enqueue( queueItem );
...
}
public TQueueItem Dequeue()
{
...
return queue.Dequeue();
...
}
}
我希望与核心实现保持一致,注意到核心队列实现了IEnumerable,所以我将通过在类上显式实现IEnumerable或使用IQueue接口继承来达到相同的效果。
我想知道的是,在枚举队列时,每个MoveNext是否都会出队下一个项?我已经使用反射器查看了Microsoft是如何做的,他们只是遍历队列的私有数组,但Microsoft远非万能,因此我想获得一个普遍意见。
public class CustomQueue<TQueueItem> : IQueue<TQueueItem>, IEnumerable<TQueueItem>
{
...
public IEnumerator<TQueueItem> GetEnumerator()
{
while (queue.Count > 0)
{
yield return Dequeue();
}
}
//Or
public IEnumerator<TQueueItem> GetEnumerator()
{
return queue.GetEnumerator();
}
...
}
我有些犹豫,一方面我认为遍历集合不应该改变集合的状态,但另一方面,特别是对于我的具体实现来说,这样做会使使用看起来更加清晰。
编辑
为了让事情更清楚。我正在实现的类在Dequeue时进行Monitor.Wait,并且队列中没有项目。当一个项目被放入队列时,就会发出Monitor.Pulse。这允许一个线程将东西推到队列中,另一个线程本质上“观察”队列。
从编程角度来看,我正在尝试决定哪种方法更干净:
foreach(QueueItem item in queue)
{
DoSomethingWithThe(item);
}
//Or
while(systemIsRunning)
{
DoSomethingWithThe(queue.Dequeue());
}
对于我的特定实现来说,如果有多个进程出列项目,也没有关系。因为它是一个队列,它们都可以选择一个项目,因为不应该处理任何项目超过一次,因此使用了队列。
编辑
有趣的是,我发现有人已经做到了这一点。
编辑
在我关闭这个问题之前,最后再尝试一下。人们对类没有实现IEnumerable但具有一个IEnumerator GetEnumerator()方法来出列项目的想法感觉如何?.net语言支持鸭子类型,foreach就是其中之一的用途。也许这值得提出自己的问题?
编辑
在另一个问题中提出了实现GetEnumerator方法而不实现IEnumerable的问题。