下面的示例在throw语句处引发IndexOutOfRangeException,因为该变量i
超出了其限制(例如,当循环覆盖0和1时为2)。我期望这段代码可以创建lambda块0和1,它们分别将结果存储在相应的数组元素中。从设置断点开始,我注意到直到我调用,异步任务才真正开始执行Task.WaitAll()
。从《C#编程指南》中,我了解到,在i
退出循环之后,编译器会竭尽全力保持作用域。
所以,我的问题是:
有人可以建议一种方法来实现我尝试创建的效果,即每个异步任务都应将其结果存储在数组中的不同插槽中?Task.Run()
没有提供参数的重载(我将用它来传递i
循环),并且lambda块声明无论如何都会阻止我尝试声明参数。
有人可以提供一个理由,为什么lambda表达式超出其声明块的作用域后才能够继续引用该局部变量是一种理想的行为吗?C#语言参考改变了“本地”声明的含义,以覆盖匿名函数和lambda块的提升,但这仅打开了获取意外值的门,如我的示例所示。
这是示例:
using System;
using System.Threading.Tasks;
namespace AsyncLifting
{
class Program
{
static void Main(string[] args)
{
const int numTasks = 2;
double[] taskResult = new double[numTasks];
Task<int>[] taskHandles = new Task<int>[numTasks];
for (int i = 0; i < numTasks; i++)
{
taskHandles[i] = Task.Run(async () =>
{
DateTime startTime = DateTime.UtcNow;
await Task.Delay(10);
try
{
taskResult[i] = (DateTime.UtcNow - startTime).TotalMilliseconds;
}
catch (Exception e) {
throw e; // IndexOutOfRange, i is 2
}
return i;
});
}
Task.WaitAll(taskHandles);
Console.WriteLine("Task waits:");
foreach (double tr in taskResult)
{
Console.WriteLine(" {0}ms.", tr);
}
}
}
}
委托正在关闭变量-它不仅在那时捕获值,而且还捕获整个变量。这有时可能有用。
无论如何,为防止意外行为,只需创建一个新变量并在块内使用它:
for(int i = 0; i < n; i++) {
int index = i;
DoSomething(delegate() {
myArray[index] = /* something */;
});
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句