确切错误:
指数超出范围。必须是非负数且小于集合的大小。
我已经无数次索引数组和列表。我已经无数次地用于数组和列表的循环。数据在那里,它的工作原理。除非我尝试为我的功能创建任务。请注意,我成功地使用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]);
,它就可以解决问题。
答案 0 :(得分:17)
任务运行时,您的任务将访问列表。不是你在循环中看到的代码行中的顺序。要确保在闭包中捕获正确的值(并且列表仍然存在且具有相同的值),请在任务之外创建本地副本,以确保在循环运行的时间点捕获值: / p>
var localAddress = addressList[i];
var localPort = portList[i];
Task.Factory.StartNew(() => PingTaskAdapted(localAddress , localPort));
答案 1 :(得分:7)
你是访问修改后的闭包的受害者,因为它被如此简洁地称为。基本上,既然你正在使用一个任务 - 而一个委托来启动 - 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]));
}
但是,正如this answer by nvoigt中所指出的,如果复制将使用的值而不是迭代器值,那么在可读性和可维护性方面就更为清晰了。
答案 2 :(得分:5)
闭包捕获变量,而非值。
将代码更改为以下内容,您将看到问题消失:
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]));
}