队列上的 IEnumerable 迭代器是否应该使项目出列

2024-04-02

我创建了一个自定义通用队列,它实现了通用 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 接口继承它来执行相同的操作。

我想知道的是,在枚举队列时,每个移动下一个项目是否都应该使下一个项目出队?我已经使用 Reflector 来了解 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();
    }

    ...
}

我有两种想法,一方面,我觉得迭代集合不应该改变集合状态,但另一方面,特别是对于我的特定实现,它会让用法看起来干净。

EDIT

将事情放在上下文中。我正在实现的类在出队时执行 Monitor.Wait 并且队列中没有项目。当一个项目被放入队列时,就会有一个 Monitor.Pulse。这允许一个线程将内容推送到队列中,而另一个线程本质上“监视”队列。

从编码的角度来看,我试图决定哪个看起来更干净:

foreach(QueueItem item in queue)
{
    DoSomethingWithThe(item);
}

//Or

while(systemIsRunning)
{
    DoSomethingWithThe(queue.Dequeue());
}

对于我的特定实现,如果有多个进程出队项目并不重要。因为它是一个队列,所以它们都可以选择一个项目,因为任何项目都不应被处理多次,因此使用队列。

EDIT

有趣的是,我发现一篇博客文章中有人已经做到了这一点。

Link https://learn.microsoft.com/en-us/archive/blogs/toub/blocking-queues

EDIT

在我结束这篇文章之前,最后一次尝试。人们对于该类没有实现 IEnumerable 但具有使项目出队的 IEnumerator GetEnumerator() 方法有何感受? .net 语言支持鸭子类型,foreach 就是其中之一。也许这值得它自己提出问题?

EDIT

提出了实现 GetEnumerator 方法而不在另一个方法中实现 IEnumerable 的问题question https://stackoverflow.com/questions/4194900/should-a-getenumerator-method-still-be-idempotent-when-the-class-does-not-implem.


迭代器应该始终是幂等的,也就是说,在迭代队列时不要修改队列。

不能保证不会有两个并发迭代......


编辑以解决您的新评论:

当另一个程序员(例如未来的你;))向代码添加功能时,他们可能不会认为迭代器是一次性的。他们可能会添加一条日志语句,在使用队列之前列出队列中的内容(哎呀)。

我刚刚想到的另一件事是 Visual Studio 调试器通常会枚举您的类以进行显示。这会导致一些极其令人困惑的错误:)

如果您正在实现 IEnumerable 的子接口,并且不想支持 IEnumerable,则应该抛出 NotSupportedException。虽然这不会给您任何编译时警告,但运行时错误将非常明显,而奇怪的 IEnumerable 实现可能会浪费您未来的时间。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

队列上的 IEnumerable 迭代器是否应该使项目出列 的相关文章

随机推荐