2013-08-24 102 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]); 
}