我想要一段测试代码,它创建一个任务集合,然后在不久的将来随机时间调用每个任务索引的方法。
我是这样写的:Random rnd = new Random();
for (Int32 taskIndex = 0; taskIndex < 10; taskIndex++)
{
_tasks.Add(String.Format("Task_{0}", taskIndex));
Progress.AddItem(_tasks[taskIndex]);
Int32 timeDelay = 5 + rnd.Next(10);
DispatcherTimer dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Interval = TimeSpan.FromSeconds(timeDelay);
dispatcherTimer.Tick += (sndr, eArgs) =>
{
dispatcherTimer.Stop();
Progress.SetItemStatus(taskIndex, Status.Executing);
};
dispatcherTimer.Start();
}
当它运行时,它总是将10传递给Progress.SetItemStatus()作为taskIndex。我明白为什么会这样(谢谢,Skeet先生) - 因为taskIndex是在匿名方法中捕获的,并在执行方法时使用它的值。
我想知道的是实现目标的最优雅方式,即在设置Tick事件时传递实例中的值。
答案 0 :(得分:3)
您正在关闭循环变量。有关详细信息,请参阅Eric Lippert’s Blog帖子。
基本上,deferred执行是使用taskIndex,它在执行时总是10(或者是最后一个值)。
Random rnd = new Random();
for (Int32 taskIndex = 0; taskIndex < 10; taskIndex++)
{
Int32 tempIndex = taskIndex;
_tasks.Add(String.Format("Task_{0}", tempIndex));
Progress.AddItem(_tasks[tempIndex]);
Int32 timeDelay = 5 + rnd.Next(10);
DispatcherTimer dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Interval = TimeSpan.FromSeconds(timeDelay);
dispatcherTimer.Tick += (sndr, eArgs) =>
{
dispatcherTimer.Stop();
Progress.SetItemStatus(tempIndex, Status.Executing);
};
dispatcherTimer.Start();
}
答案 1 :(得分:0)
我只是在这里猜测(还没有真正测试过这个),如果你在for循环代码中分配一个应该捕获迭代值的本地值。
Random rnd = new Random();
for (Int32 taskIdx = 0; taskIdx < 10; taskIdx++)
{
var taskIndex = taskIdx;
_tasks.Add(String.Format("Task_{0}", taskIndex));
Progress.AddItem(_tasks[taskIndex]);
Int32 timeDelay = 5 + rnd.Next(10);
DispatcherTimer dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Interval = TimeSpan.FromSeconds(timeDelay);
dispatcherTimer.Tick += (sndr, eArgs) =>
{
dispatcherTimer.Stop();
Progress.SetItemStatus(taskIndex, Status.Executing);
};
dispatcherTimer.Start();
}
这是为了捕捉“这个”的价值而共同完成的。