Исключить из списка исключение из диапазона при создании задачи
Точная ошибка:
Индекс оказался вне допустимого диапазона. Должен быть неотрицательным и меньше размера коллекции.
У меня есть массивы индексов и списки бесчисленных раз. Я использовал для циклов с массивами и списками бесчисленное количество раз. Данные есть, он работает. За исключением случаев, когда я пытаюсь создать задачу для своей функции. Имейте в виду, я успешно сделал это с петлей 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]
- google.com, а portList[0]
- 80,
Выход:
Address List Length: 1
Task for google.com:80 initiated.
затем перерыв программы, с Visual Studio, который говорит мне, что в PingTaskAdapted() я вызываю индекс, который выходит за пределы диапазона, когда он буквально просто печатает указанные индексы, потому что они существуют.
И просто чтобы быть ясным, если я звоню PingTaskAdapted(addressList[0], pingList[0]);
, он не будет работать без проблем.
Ответы
Ответ 1
Ваша задача будет получать доступ к списку при запуске задачи. Не последовательно в строке кода, который вы смотрите в цикле. Чтобы убедиться, что правильные значения зафиксированы в закрытии (и списки все еще существуют и имеют одинаковые значения), создайте локальные копии вне задачи, чтобы убедиться, что значения будут отсчитываться в тот момент времени цикла:
var localAddress = addressList[i];
var localPort = portList[i];
Task.Factory.StartNew(() => PingTaskAdapted(localAddress , localPort));
Ответ 2
Вы становитесь жертвой доступа к модифицированному закрытию, так как он так лаконично называется. В принципе, поскольку вы используете задачу - и делегат для загрузки - значение 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, гораздо яснее, когда речь заходит о читаемости и ремонтопригодности, если вы скопируете значения, которые будут использоваться, а не значение итератора.
Ответ 3
Закрывает захват переменных, а не значений.
Измените код на следующий, и вы увидите, что проблема исчезнет:
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]));
}