Должен ли итератор IEnumerable в очереди исключать элемент из очереди

Я создал настраиваемую общую очередь, которая реализует универсальный интерфейс IQueue, который использует универсальную очередь из пространства имен System.Collections.Generic в качестве частной внутренней очереди. Пример был очищен от нерелевантного кода.

public interface IQueue
{
    void Enqueue(TQueueItem queueItem);
    TQueueItem Dequeue();
}

public class CustomQueue : IQueue
{
    private readonly Queue queue = new Queue();
    ...
    public void Enqueue(TQueueItem queueItem)
    {
        ...
        queue.Enqueue( queueItem );
        ...
    }

    public TQueueItem Dequeue()
    {
        ...
        return queue.Dequeue();
        ...
    }
}

Я хочу сохранить согласованность с основными реализациями и заметил, что основная очередь реализует IEnumerable, поэтому я сделаю то же самое, либо явно реализуя IEnumerable в классе, либо унаследовав его с помощью IQueue интерфейс.

Что я хочу знать, так это то, что при перечислении по очереди должно ли каждое движение выводить из очереди следующий элемент? Я использовал рефлектор, чтобы увидеть, как Microsoft это сделала, и все, что они делают, это просматривают частный массив очередей, но Microsoft далеко не безупречна, поэтому я хотел получить общее мнение.

public class CustomQueue : IQueue, IEnumerable
{
    ...

    public IEnumerator GetEnumerator()
    {
        while (queue.Count > 0)
        {
            yield return Dequeue();
        }
    }

    //Or

    public IEnumerator GetEnumerator()
    {
        return queue.GetEnumerator();
    }

    ...
}

У меня двоякое мнение, с одной стороны, я чувствую, что итерация по коллекции не должна изменять ее состояние, но с другой стороны, особенно с моей конкретной реализацией, это сделает использование более чистым.

EDIT

Чтобы поместить вещи в контекст. Реализуемый мной класс выполняет Monitor.Wait при выводе из очереди, и в очереди нет элементов. Когда элемент помещается в очередь, появляется Monitor.Pulse. Это позволяет одному потоку помещать данные в очередь, а другому, по сути, «наблюдать» за ней.

С точки зрения кодирования я пытаюсь решить, что выглядит чище:

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

//Or

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

Для моей конкретной реализации не имело бы значения, если бы было несколько элементов вывода из очереди процесса. Поскольку это очередь, они оба могут выбрать элемент, поскольку ни один элемент не должен обрабатываться более одного раза, отсюда и использование очереди.

EDIT

Достаточно интересно, что я нашел сообщение в блоге, где кто-то сделал именно это .

http://blogs.msdn.com/b/toub/archive/2006/04/12/blocking-queues.aspx

ИЗМЕНИТЬ

Последний удар, прежде чем я закрою это. Как люди относятся к классу, который не реализует IEnumerable, но имеет метод IEnumerator GetEnumerator (), который удаляет элементы из очереди? Язык .net поддерживает утиную типизацию, причем foreach является одним из вариантов использования. Возможно, это того заслуживает ' собственный вопрос?

РЕДАКТИРОВАТЬ

Вопрос о реализации метода GetEnumerator без реализации IEnumerable был поднят в другом вопросе .

15
задан Community 23 May 2017 в 11:45
поделиться