创建任务时列出索引超出范围异常

时间:2017-07-12 09:11:38

标签: c# lambda task indexoutofboundsexception indexoutofrangeexception

确切错误:

  

指数超出范围。必须是非负数且小于集合的大小。

我已经无数次索引数组和列表。我已经无数次地用于数组和列表的循环。数据在那里,它的工作原理。除非我尝试为我的功能创建任务。请注意,我成功地使用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]);,它就可以解决问题。

3 个答案:

答案 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]));
    }