Исключение List Index Out of Range при создании задачи
точная ошибка:
индекс был вне диапазона. Должен быть неотрицательным и меньше размера коллекции.
у меня есть массивы индексов и списки бесчисленное количество раз. Я использовал для циклов с массивами и списками бесчисленное количество раз. Данные есть, они работают. Кроме тех случаев, когда я пытаюсь создать задачу для своей функции. Заметьте, я успешно сделал это с циклом foreach для аналогичной функции; этот новый требует двух аргументов, поэтому я не могу использовать цикл foreach правильно. По крайней мере, я так думаю.
вот ошибочный код:
if (addressList != null) {
textBox1.Text += ("Address List Length: " + addressList.Count + Environment.NewLine);
for (int i = 0; i < addressList.Count; i++) {
textBox1.Text += ("Task for " + addressList[i] + ":" + portList[i] + " initiated." + Environment.NewLine);
Task.Factory.StartNew(() => PingTaskAdapted(addressList[i], portList[i]));
}
}
else textBox1.Text = ("No IPs have been added.");
предполагая, что addressList[0]
is google.com и portList[0]
- это 80,
Вывод:
Address List Length: 1
Task for google.com:80 initiated.
затем перерыв программы, с Visual Studio говорит мне, что в PingTaskAdapted() я вызываю индекс, который находится вне диапазона, когда он буквально просто напечатал индексы, о которых идет речь, потому что они существуют.
и просто для ясности, если я позвоню PingTaskAdapted(addressList[0], pingList[0]);
это работает без проблем.
3 ответов
ваша задача будет доступ к списку при выполнении задачи. Не последовательно в строке кода, на которую вы смотрите в цикле. Чтобы убедиться, что правильные значения захвачены в закрытии (а списки все еще существуют и имеют те же значения), сделайте локальные копии вне задачи, которые убедитесь, что значения захвачены в тот момент времени, когда цикл выполняется:
var localAddress = addressList[i];
var localPort = portList[i];
Task.Factory.StartNew(() => PingTaskAdapted(localAddress , localPort));
вы жертва доступа к измененному закрытию, как это так лаконично называется. В принципе, поскольку вы используете задачу-и делегат для загрузки-значение i
не гарантируется, что это будет то, что вы ожидаете. Если вы, однако, копируете i
для локальной переменной, определенной для области одной, одной итерации, вы должны быть в порядке.
for (int i = 0; i < addressList.Count; i++)
{
textBox1.Text += ("Task for " + addressList[i] + ":" + portList[i] + " initiated." + Environment.NewLine);
var iCopy = i;
Task.Factory.StartNew(() => PingTaskAdapted(addressList[iCopy], portList[iCopy]));
}
Однако, как указано в этот ответ nvoigt, это гораздо более ясно, когда дело доходит до читаемость и ремонтопригодность при копировании значений, которые будут использоваться, а не итератор значение.
закрытие захвата переменные, а не значения.
измените код на следующий, и вы увидите, что проблема исчезнет:
for (int i = 0; i < addressList.Count; i++) {
textBox1.Text += ("Task for " + addressList[i] + ":" + portList[i] + " initiated." + Environment.NewLine);
var temp = i;
Task.Factory.StartNew(() => PingTaskAdapted(addressList[temp], portList[temp]));
}