c# - 如何通过 lambda 表达式传递捕获的变量,就好像它未被捕获一样?

标签 c# closures anonymous-methods

我想要一段测试代码,它创建任务集合,然后在不久的将来的某个随机时间调用每个任务索引的方法。

我是这样写的:

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()。我明白为什么会这样(谢谢,Skeet 先生) - 因为 taskIndex 是在匿名方法中捕获的,并在执行方法时使用它的值。

我想知道的是实现我的目标的最优雅的方法,即在设置 Tick 事件时传递实例中的值。

最佳答案

您正在关闭循环变量。请参阅Eric Lippert’s Blog发帖获取更多信息。

基本上,延迟执行使用的是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();
}

关于c# - 如何通过 lambda 表达式传递捕获的变量,就好像它未被捕获一样?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16864406/

相关文章:

c# - 为同一个匿名方法创建两个委托(delegate)实例不相等

delphi - 在Delphi 2009中使用泛型和匿名方法有什么问题?

c# - Visual Studio 丢失/移动了我的断点

c# - Visual Studio 2010 Pro,在应用程序关闭时不结束 Debug模式

c# - 关闭范围和垃圾收集

JavaScript:引用 'this' 关键字的闭包

delphi - 匿名方法的 TypeInfo 的奇怪行为

c# - 将字符串格式化为 3 位数字

c# - ASP.NET 中 OnInit 和 OnLoad 的区别?

ios - 函数返回后调用转义闭包是什么意思?