2013-08-24 10 views
7

Questo può essere fatto in un ciclo for?Metodo anonimo per il gestore di eventi in loop

 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); 

Questo non funziona perché i è fuori dai limiti (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

Te lo dice l'espressione lambda; 'i' è condiviso da tutti loro. Nel momento in cui la funzione viene eseguita, vengono essenzialmente chiamati 'timer [i] .Tick + = (sender, e) => Tick (targs [5])'. Dichiara un locale 'int locali = i' e usalo invece nella tua linea. –

+0

@ChrisSinclair pubblicalo come risposta. – I4V

+0

possibile duplicato di [C# Captured Variable In Loop] (http://stackoverflow.com/questions/271440/c-sharp-captured-variable-in-loop) – nawfal

risposta

10

Questo viene dall'espressione lambda; iis shared between all of them. Nel momento in cui la funzione viene eseguita, vengono essenzialmente chiamati come timers[i].Tick += (sender, e) => Tick(targs[5]).

Per evitare ciò, creare una variabile locale con scope (int locali = i) e utilizzarla invece nella linea. Questo assicurerà che ogni espressione lambda abbia effettivamente il valore che ti aspetti.

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

i diventa 5 dal l'ultima iterazione del ciclo prima di uscire. Naturalmente, non si dispone di un elemento targs[5], quindi genera uno IndexOutOfRangeException.

Tecnicamente, non è necessario utilizzare locali per la parte timers[i].Tick poiché viene valutata immediatamente, ma personalmente trovo confuso il mix dei due.


qualche lettura supplementare sul Concepet:

The foreach identifier and closures

Closing over the loop variable considered harmful

+0

Grazie per la risposta rapida. Funziona come dovrebbe ora. A proposito, sai se c'è un modo per semplificare l'assegnazione degli array, cioè tutti i targ si farebbero in un'unica istruzione? – dirtyw0lf

+0

@ dirtyw0lf: Ma li hai tutti assegnati a diversi timer. Volevi davvero solo un timer _single_ per cancellare l'intero array 'targs'? –

+0

No, mi chiedo solo se potrei farlo in un passaggio per tutti i timer per l'assegnazione di array – dirtyw0lf

8

C'è un solo i in questo caso e tutti i lambda sono catturare lo stesso valore. Utilizzare un locale che ha come ambito il ciclo in modo che ogni lambda ha una copia diversa

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