Я бачу тут різні шматочки правильної відповіді, але дозвольте зібрати все разом і пояснити кілька речей.
Перш за все, AcceptChanges
слід використовувати лише для позначення всієї транзакції в таблиці як перевірену та здійснену. Це означає, що якщо ви використовуєте DataTable як джерело даних для прив’язки, наприклад, до SQL-сервера, тоді виклик AcceptChanges
вручну гарантуватиме, що зміни ніколи не будуть збережені на SQL-сервері .
Що робить це питання більш заплутаним, так це те, що насправді є два випадки, коли виняток створюється, і ми повинні запобігти обом.
1. Модифікація колекції IEnumerable
Ми не можемо додати чи видалити індекс до переліченої колекції, оскільки це може вплинути на внутрішнє індексування перечислювача. Є два способи обійти це: або зробити власне індексування в циклі for, або використовувати окрему колекцію (яка не модифікується) для перерахування.
2. Спроба прочитати видалений запис
Оскільки таблиці даних є колекціями транзакцій , записи можна позначити для видалення, але все одно відображатимуться в переліку. Це означає, що якщо ви запитаєте видалений запис для стовпця, "name"
він видасть виняток. Це означає, що ми повинні перевірити, чи є dr.RowState != DataRowState.Deleted
перед запитом стовпець.
Склавши все це разом
Ми можемо заплутатись і зробити все це вручну, або ми можемо дозволити DataTable зробити всю роботу за нас і зробити виписку виглядаючою і схожою на виклик SQL, виконавши наступне:
string name = "Joe";
foreach(DataRow dr in dtPerson.Select($"name='{name}'"))
dr.Delete();
Викликаючи Select
функцію DataTable , наш запит автоматично уникає вже видалених записів у DataTable. І оскільки Select
функція повертає масив збігів, колекція, яку ми перераховуємо, не змінюється, коли ми викликаємо dr.Delete()
. Я також приправив вираз Select інтерполяцією рядків, щоб дозволити вибір змінних, не роблячи код шумним.
[ii]
на[i]
:-)