Я создал пользовательскую общую очередь, которая реализует общий интерфейс 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();
...
}
}
Я хочу, чтобы все было согласовано с основными реализациями, и заметили, что основная Queue реализует IEnumerable, поэтому я буду делать то же самое, явно используя IEnumerable в классе или наследуя его с помощью интерфейса IQueue.
То, что я хочу знать, - это когда перечисление в очереди должно проходить каждый следующий разворачивать следующий элемент? Я использовал рефлектор, чтобы увидеть, как 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();
}
...
}
Я нахожусь в двух умах, с одной стороны, я чувствую, что итерация через коллекцию не должна изменять состояние коллекций, но, с другой стороны, и особенно с моей конкретной реализацией, это сделает использование понятным.
ИЗМЕНИТЬ
Вставить вещи в контекст. Класс, который я реализую, выполняет Monitor.Wait, когда Dequeuing и нет элементов в очереди. Когда элемент помещается в очередь, появляется Monitor.Pulse. Это позволяет одному потоку подталкивать материал в очередь, а другой - "смотреть" очередь.
С точки зрения кодирования я пытаюсь решить, какой из них выглядит более чистым:
foreach(QueueItem item in queue)
{
DoSomethingWithThe(item);
}
//Or
while(systemIsRunning)
{
DoSomethingWithThe(queue.Dequeue());
}
Для моей конкретной реализации не имело бы значения, было ли несколько объектов, связанных с процессом. Поскольку это очередь, они могут оба выбрать элемент, так как ни один элемент не должен обрабатываться более одного раза, следовательно, использование очереди.
ИЗМЕНИТЬ
Интересно, что я нашел сообщение в блоге, где кто-то сделал именно это.
http://blogs.msdn.com/b/toub/archive/2006/04/12/blocking-queues.aspx
ИЗМЕНИТЬ
Один последний удар в этом, прежде чем я закрою это. Как люди чувствуют, что класс не реализует IEnumerable, но имеет метод IEnumerator GetEnumerator(), который отменяет элементы? Язык .net поддерживает утиную печать, foreach является одним из видов использования. Возможно, это заслуживает собственного вопроса?
ИЗМЕНИТЬ
Возник вопрос о внедрении метода GetEnumerator без реализации IEnumerable в другом question.