Ответ 1
Похоже, вы хотите LinkedList<T>
, который позволяет делать такие вещи, как AddFirst()
, AddLast()
, RemoveFirst()
и RemoveLast()
.
Я создаю службу Windows, которая использует FileSystemWatcher для контроля конкретной папки для добавления определенного типа файла. Из-за разрыва между созданным событием и когда файл действительно готов к обработке, я создал Queue<T>
для хранения имен файлов, которые нуждаются в обработке. В обработчике созданного события элемент добавляется в очередь. Затем, используя таймер, я периодически захватываю первый элемент из очереди и обрабатываю его. Если обработка завершается неудачно, элемент добавляется обратно в очередь, чтобы служба могла повторить обработку позже.
Это отлично работает, но я обнаружил, что у него есть один побочный эффект: первая попытка обработки новых элементов происходит не до тех пор, пока все старые элементы повторной попытки не будут повторены. Поскольку возможно, что очередь может содержать много элементов, я бы хотел, чтобы новые элементы были впереди очереди, чтобы они обрабатывались первыми. Но из Queue<T>
документации нет очевидного способа добавления элемента в очередь.
Я предполагаю, что я мог бы создать вторую очередь для новых элементов и обработать, что один предпочтительнее, но с одной очередью кажется более простым.
Итак, есть ли простой способ добавить элемент в очередь?
Похоже, вы хотите LinkedList<T>
, который позволяет делать такие вещи, как AddFirst()
, AddLast()
, RemoveFirst()
и RemoveLast()
.
Просто используйте метод Peek в обратном вызове таймера вместо Dequeue. Если обработка завершается успешно, то вычеркните элемент.
Хорошо, я согласен с CanSpice; однако вы могли бы:
var items = queue.ToArray();
queue.Clear();
queue.Enqueue(newFirstItem);
foreach(var item in items)
queue.Enqueue(item);
Неприятный взлом, но он будет работать;)
Скорее вы можете подумать о добавлении второго экземпляра очереди. Это одна очередь приоритетов, которую вы проверяете/выполняете в первую очередь. Это было бы немного чище. Вы даже можете создать свой собственный класс очереди, чтобы обернуть все это красиво и аккуратно;)
Похоже, что вы находитесь после Stack - это буфер LIFO (последний, первый).
Я бы предложил использовать две очереди: одну для новых элементов и одну для элементов повторной попытки. Оберните обе очереди в одном объекте, который имеет ту же семантику, что и очередь, до удаления, но позволяет отмечать вещи как входящие в очередь New или очередь Retry при вставке. Что-то вроде:
public class DoubleQueue<T>
{
private Queue<T> NewItems = new Queue<T>();
private Queue<T> RetryItems = new Queue<T>();
public Enqueue(T item, bool isNew)
{
if (isNew)
NewItems.Enqueue(item);
else
RetryItems.Enqueue(item);
}
public T Dequeue()
{
if (NewItems.Count > 0)
return NewItems.Dequeue();
else
return RetryItems.Dequeue();
}
}
Конечно, вам нужно иметь свойство Count
, которое возвращает количество элементов в обеих очередях.
Если у вас есть более двух типов элементов, тогда пришло время перейти на приоритетную очередь.
Вам нужна очередь приоритетов. Взгляните на C5 Collections Library. IntervalHeap реализует интерфейс IPriorityQueue. Библиотека коллекций C5 тоже очень хороша.
Я считаю, что вы можете найти реализации в http://www.codeproject.com и http://www.codeplex.com.