2013-08-24 104 views
7

这可以在for循环中完成吗?for循环中的事件处理程序的匿名方法

 TickEventArgs targs1 = new TickEventArgs(lbl1_up_time, _elapsedTime_up1); 
     timer_up1.Tick += (sender, e) => Tick(targs1); 

     TickEventArgs targs2 = new TickEventArgs(lbl2_up_time, _elapsedTime_up2); 
     timer_up2.Tick += (sender, e) => Tick(targs2); 

     TickEventArgs targs3 = new TickEventArgs(lbl3_up_time, _elapsedTime_up3); 
     timer_up3.Tick += (sender, e) => Tick(targs3); 

     TickEventArgs targs4 = new TickEventArgs(lbl4_up_time, _elapsedTime_up4); 
     timer_up4.Tick += (sender, e) => Tick(targs4); 

     TickEventArgs targs5 = new TickEventArgs(lbl5_up_time, _elapsedTime_up5); 
     timer_up5.Tick += (sender, e) => Tick(targs5); 

这不工作,因为我是出界(5)

 targs[0] = new TickEventArgs(lbl1_up_time, _elapsedTime_up1); 
     targs[1] = new TickEventArgs(lbl2_up_time, _elapsedTime_up2); 
     targs[2] = new TickEventArgs(lbl3_up_time, _elapsedTime_up3); 
     targs[3] = new TickEventArgs(lbl4_up_time, _elapsedTime_up4); 
     targs[4] = new TickEventArgs(lbl5_up_time, _elapsedTime_up5); 

     timers[0] = timer_up1; 
     timers[1] = timer_up2; 
     timers[2] = timer_up3; 
     timers[3] = timer_up4; 
     timers[4] = timer_up5; 

     int i = 0; 

     for (i = 0; i <= 4; i++) 
     { 
      timers[i].Tick += (sender, e) => Tick(targs[i]); 
     } 
+0

这是从λ表达式来; “我”是所有人共享的。当函数被执行时,它们基本上被称为'timers [i] .Tick + =(sender,e)=> Tick(targs [5])''。声明一个本地'int locali = i',并用它代替你的行。 –

+0

@ChrisSinclair将其作为答案发布。 – I4V

+0

[C#Captured Variable In Loop]的可能重复(http://stackoverflow.com/questions/271440/c-sharp-captured-variable-in-loop) – nawfal

回答

10

这是来自lambda表达式; iis shared between all of them。在执行函数时,它们基本上被称为timers[i].Tick += (sender, e) => Tick(targs[5])

为了避免这种情况,请创建一个本地作用域变量(int locali = i),然后在您的行中使用该变量。这将确保每个lambda表达式实际上获得您期望的值。

for (i = 0; i <= 4; i++) 
{ 
    int locali = i; 
    timers[locali].Tick += (sender, e) => Tick(targs[locali]); 
} 

i从退出前的循环的最后一次迭代中变为5。当然,你没有targs[5]元素,所以它会抛出一个IndexOutOfRangeException

从技术上讲,您不需要为timers[i].Tick零件使用locali零件,因为它会立即进行评估,但我个人发现混淆这两者是令人困惑的。


在concepet一些额外的读数:

The foreach identifier and closures

Closing over the loop variable considered harmful

+0

感谢您的快速回答。按现在的样子工作。顺便说一句,你知道是否有一种方法来简化数组的分配,即所有的targs将在一个语句中完成? – dirtyw0lf

+0

@ dirtyw0lf:但您已将它们全部分配给不同的定时器。你真的只想要一个_single_定时器来清除整个'targs'数组吗? –

+0

不,只是想知道我是否可以一次性完成数组赋值操作 – dirtyw0lf

8

只有一个i在这种情况下,所有的lambda表达式正在捕获相同的值。使用作用于循环的本地,以便每个lambda具有不同的副本

for (i = 0; i <= 4; i++) 
{ 
    int j = i; 
    timers[j].Tick += (sender, e) => Tick(targs[j]); 
}