2015-04-11 3 views
4

Итак, я работаю над консольным приложением, которое извлекает из API каждые 3 секунды. API возвращает список «Сообщения», который мне нужно добавить в очередь, и что-то в фоновом режиме постоянно проверяет наличие новых элементов в очереди, перебирает элементы, делает что-то с элементами.Использование очереди в C#?

Вот то, что я до сих пор: Основная программа Метод

static void Main(string[] args) 
{ 
    ConsoleKeyInfo answer = Console.ReadKey(true); 
    if (answer.Key == ConsoleKey.Y) 
    { 
     while (true) 
     { 
      foreach (MessageObject message in messageQueue) 
      { 
       SendCommand(message.Message); 

       // Debug 
       Console.WriteLine(message.Message); 
       messageQueue.Dequeue(); 
      } 
     } 
    } 
    else 
    { 
     Environment.Exit(0); 
    } 
} 

CheckChat Метод

static private async void CheckChat() 
{ 
    Chat chat = await ChatAPI.GetChat(428); 

    foreach (MessageObject chatMessage in chat.Messages) 
    { 
     messageQueue.Enqueue(chatMessage); 
    } 
} 

Однако, я получаю следующее сообщение об ошибке:

An unhandled exception of type 'System.InvalidOperationException' occurred in System.dll

Additional information: Collection was modified after the enumerator was instantiated.

Я понимаю, что я добавляю элементы в список во время цикла в очереди, но как я буду постоянно проверять элементы в очереди в качестве им добавления объектов?

+0

это означает, что вы не можете ставить в очередь во время перечисления – Legends

+0

@Legends Правильно, но если im всегда (каждые x секунд), необходимо добавить элементы в мою очередь из API, как бы я это сделал? –

+0

Скорее всего, ваша асинхронность меняет содержимое messageQueue, пока вы заняты. Почему бы вам не попробовать и просто проверить размер (длину), а затем прочитать по одному. .... или, как сказал Бен, создать копию и прочитать ее. –

ответ

6

Вам нужно создать копию очереди, если вы хотите, чтобы перечислить его в то время как она модифицируется, например, вы можете:

foreach (MessageObject message in messageQueue.ToList()) 

Обратите внимание, что во все вероятности вашей очередь также должна быть ConcurrentQueue, поскольку вы «Выполнение операций по потокам.

+0

В качестве подсказки - я бы подумал о том, чтобы использовать ReactiveExtensions, если бы я был вами, это намного более элегантный, чем цикл while (true), лучше работает, поскольку он не занят ожиданиями и лучше передает намерения. На мой взгляд, это определенно стоит изучить. –

+0

Я все еще сталкиваюсь с ошибкой здесь: http://prntscr.com/6slvyi, и я обязательно буду считать это, спасибо! –

+0

@EliteGamer вы используете 'ConcurrentQueue'? Обычные очереди будут, безусловно, терпеть неудачу из-за использования сквозных потоков, поскольку они не являются [потоковой безопасностью] (https://msdn.microsoft.com/en-us/library/dd997305%28v=vs.110%29 .aspx). (Т. Е. Коллекция изменяется _while_ выполняется 'ToList()' –

0

Вы можете использовать (например) петлю while вместо foreach:

while (messageQueue.Count != 0) 
{ 
    MessageObject message = messageQueue.Dequeue(); 
    Console.WriteLine(message.Message); 
} 

В этом случае нет никаких проблем с изменением очереди.

Смежные вопросы