Как справиться с этой ошибкой: коллекция была изменена; операция перечисления может не выполняться.
Здравствуйте Эксперты
В моем проекте я создаю много транзакций и храню их в dataGridView вместе с их деталями.
При нажатии кнопки startbtn этот код будет выполнен:
Manager manager = new Manager(GridView);
А вот и класс менеджера:
public class Manager { public static Dictionary<Thread, int> ThreadList; public static DataTable DisposableThreads; public Manager(DataGridView dgv) { ThreadList = new Dictionary<Thread, int>(); DisposableThreads = new DataTable(); DisposableThreads.Columns.Add(new DataColumn("Thread", typeof(Thread))); DisposableThreads.RowChanged += RowChanged; foreach (DataGridViewRow row in dgv.Rows) { Thread thread = new Thread(() => Transaction(dgv, (row as GridRow).Row)); ThreadList.Add(thread, (row as GridRow).Row); thread.Start(); } } private void RowChanged(object sender, DataRowChangeEventArgs e) { if (e.Action == DataRowAction.Add) { ThreadList.Remove((Thread)e.Row.ItemArray[0]); DisposableThreads.Rows.Remove(e.Row); } } public void Transaction(DataGridView dataGridView, int row) { // Some Code DisposableThreads.Rows.Add(new object[] { Thread.CurrentThread }); } }
Все идет прекрасно.
Но иногда, когда я нажимаю кнопку stop, чтобы отменить запущенные потоки, происходит следующий exeception.
Collection was modified; enumeration operation may not execute.
Код в кнопке Стоп таков:
private void Stop_Click(object sender, EventArgs e) { try { foreach (Thread t in Manager.ThreadList.Keys) { if (t.ThreadState == System.Threading.ThreadState.Running) t.Abort(); // they really do not abort by this code !!?? } MessageBox.Show("All operations canceled successfully."); } catch (Exception ex) { MessageBox.Show(ex.Message); } }
johannesnestler
Sounds like a little confusion cause threads are involved etc. But the cause of the error is quite simple. You are changing a collection while you are enumerating it - this is not allowed in C#. Ashok Rathod showed you a way to circumenvent this problem by creating a temp list... I just want to add the answer to your commented question: No, Thread.Abort just throws an exception on the aborted thread, you have to handle the exception in your threads code for yourself. So nothing will be aborted (but it will may fail due unhandled excpetion) if you don't "react" to it in your code. The best advice if in doubt: have a look at MSDN! (Thread.Abort is well documented, as most parts of .NET Framework are)
Meysam Tolouee
Я знаю, что причина ошибки проста. Что не так просто, так это ответ.
johannesnestler
Привет Мейсам,
Теперь, когда я поближе присмотрелся к решению Ашока, я увидел проблему. Вы должны создать независимую(!) коллекцию с потоками для прерывания (своего рода моментальный снимок в то время). После этого попробуйте прервать все потоки, не перечисляя новую независимую коллекцию (используйте цикл for,а не foreach).
Meysam Tolouee
Смотрите мое решение.