2013-08-24 5 views
7

के लिए इवेंट हैंडलर के लिए बेनामी विधि यह लूप के लिए किया जा सकता है?लूप

 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

यह लैम्ब्डा अभिव्यक्ति से आ रही है; 'i' उन सभी के बीच साझा किया जाता है। जब तक कार्य निष्पादित किया जाता है तब तक उन्हें अनिवार्य रूप से 'टाइमर [i] कहा जाता है। टिक + = (प्रेषक, ई) => टिक (टैग्स [5]) '। एक स्थानीय 'int locali = i' घोषित करें और इसके बजाय अपनी लाइन में इसका उपयोग करें। –

+0

@ChrisSinclair इसे उत्तर के रूप में पोस्ट करें। – I4V

+0

[सी # कैप्चर वैरिएबल इन लूप] के संभावित डुप्लिकेट (http://stackoverflow.com/questions/271440/c-sharp-captured-variable-in-loop) – nawfal

उत्तर

10

यह लैम्ब्डा अभिव्यक्ति से आ रही है है; iis shared between all of them। जब तक कार्य निष्पादित किया जाता है तब तक उन्हें अनिवार्य रूप से timers[i].Tick += (sender, e) => Tick(targs[5]) कहा जाता है।

इससे बचने के लिए, स्थानीय रूप से स्कॉप्ड चर (int locali = i) बनाएं और इसके बजाय अपनी लाइन में इसका उपयोग करें। यह सुनिश्चित करेगा कि प्रत्येक लैम्ब्डा अभिव्यक्ति वास्तव में आपके द्वारा अपेक्षित मूल्य प्राप्त करेगी।

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

त्वरित उत्तर के लिए धन्यवाद। जैसा कि अब करना चाहिए बीटीडब्ल्यू, क्या आपको पता है कि सरणी के असाइनमेंट को सरल बनाने का कोई तरीका है, यानी सभी टैग एक कथन में किए जाएंगे? – dirtyw0lf

+0

@ dirtyw0lf: लेकिन आप सभी को अलग-अलग टाइमर को सौंपा गया है। क्या आप वास्तव में पूरे 'targs' सरणी को साफ़ करने के लिए सिर्फ _single_ टाइमर चाहते थे? –

+0

नहीं, बस सोच रहा है कि क्या मैं इसे सरणी असाइनमेंट – dirtyw0lf

8

सिर्फ एक ही i इस मामले में और lambdas के सभी एक ही मूल्य पर कब्जा कर रहे हैं। एक स्थानीय है कि पाश के दायरे वाला प्रयोग करें ताकि प्रत्येक लैम्ब्डा एक अलग प्रतिलिपि

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