创建任务时List Index Out of Range异常
List Index Out of Range exception when creating a task
确切错误:
Index was out of range. Must be non-negative and less than the size of the collection.
我有无数次索引数组和列表。我无数次使用数组和列表进行循环。数据在那里,它起作用了。除非我尝试为我的函数创建任务。请注意,我使用类似功能的 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]);
它没有任何问题。
您是访问修改后的闭包的受害者,因为它是如此简洁地被称为。基本上,由于您正在使用任务 - 和委托来启动 - 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]));
}
然而,正如 中所指出的,如果您复制将要使用的值而不是迭代器值,那么在可读性和可维护性方面要清楚得多。
您的任务将在任务运行时访问列表。在循环中查看的代码行中没有顺序。为了确保在闭包中捕获了正确的值(并且列表仍然存在并具有相同的值),在任务之外制作本地副本,以确保在循环运行的那个时间点捕获值:
var localAddress = addressList[i];
var localPort = portList[i];
Task.Factory.StartNew(() => PingTaskAdapted(localAddress , localPort));
闭包捕获变量,而不是值。
将代码更改为以下内容,您会发现问题消失了:
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]));
}
确切错误:
Index was out of range. Must be non-negative and less than the size of the collection.
我有无数次索引数组和列表。我无数次使用数组和列表进行循环。数据在那里,它起作用了。除非我尝试为我的函数创建任务。请注意,我使用类似功能的 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]);
它没有任何问题。
您是访问修改后的闭包的受害者,因为它是如此简洁地被称为。基本上,由于您正在使用任务 - 和委托来启动 - 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]));
}
然而,正如
您的任务将在任务运行时访问列表。在循环中查看的代码行中没有顺序。为了确保在闭包中捕获了正确的值(并且列表仍然存在并具有相同的值),在任务之外制作本地副本,以确保在循环运行的那个时间点捕获值:
var localAddress = addressList[i];
var localPort = portList[i];
Task.Factory.StartNew(() => PingTaskAdapted(localAddress , localPort));
闭包捕获变量,而不是值。
将代码更改为以下内容,您会发现问题消失了:
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]));
}