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

Posted

技术标签:

【中文标题】创建任务时列出索引超出范围异常【英文标题】:List Index Out of Range exception when creating a task 【发布时间】:2017-12-16 15:01:53 【问题描述】:

确切的错误:

索引超出范围。必须为非负数且小于集合的大小。

我无数次索引数组和列表。我已经无数次使用带有数组和列表的循环。数据在那里,它有效。除非我尝试为我的函数创建任务。请注意,我使用 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]);,它可以正常工作。

【问题讨论】:

你应该使用Enumerable.Zip 【参考方案1】:

你是访问修改闭包的受害者,因为它被简洁地称为。基本上,由于您使用的是任务 - 以及启动的委托 - 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】:

闭包捕获变量,而不是

将代码更改为以下内容,您将看到问题消失:

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]));
                    

【讨论】:

【参考方案3】:

当任务运行时,您的任务将访问列表。在您在循环中查看的代码行中不是按顺序排列的。为了确保在闭包中捕获正确的值(并且列表仍然存在并且具有相同的值),请在任务之外制作本地副本,以确保在循环运行的那个时间点捕获值:

var localAddress = addressList[i];
var localPort = portList[i];
Task.Factory.StartNew(() => PingTaskAdapted(localAddress , localPort));

【讨论】:

我更喜欢这种方式,尽管我有自己的回答(为了清楚修改了哪个变量,我写了我这样做的方式)。这个答案的代码 sn-p 非常清楚哪个值将用于任务执行。 这是一个很奇怪的现象。有趣的学习。我的代码现在确实可以工作了,谢谢。

以上是关于创建任务时列出索引超出范围异常的主要内容,如果未能解决你的问题,请参考以下文章

读取csv python时列出索引超出范围

C# -Task.Run() 中线程池中的索引超出范围异常

将类添加到列表 C# 时,索引超出了数组的范围

IndexError:使用beautifulsoup 抓取广告时列出的索引超出范围

Java:创建没有匹配连续字符的字符串时索引超出范围的异常

IndexError:在pyspark shell上使用reduceByKey操作时列出索引超出范围