2012-03-05 20 views
6

मैं समझ नहीं पा रहा हूं कि Action सूची के माध्यम से लूप कैसे करें। जब मैं इसे आज़माता हूं, तो मैं मानों को पिछले पुनरावृत्ति के समान ही समाप्त करता हूं।क्रियाओं की सूची के माध्यम से लूपिंग

यहाँ कोड (सरलीकृत उदाहरण) है:

string[] strings = { "abc", "def", "ghi" }; 

var actions = new List<Action>(); 
foreach (string str in strings) 
    actions.Add(new Action(() => { Trace.WriteLine(str); })); 

foreach (var action in actions) 
    action(); 

आउटपुट:

ghi 
ghi 
ghi 

क्यों यह हमेशा strings में अंतिम तत्व को चुन रही है जब यह कार्रवाई करता है?
और मैं वांछित आउटपुट जो होगा कैसे प्राप्त कर सकते हैं:

abc 
def 
ghi 

उत्तर

13

आपकी कार्रवाई को बंद करने की है, इसलिए उसके द्वारा पहुंच str ही है, नहीं str की एक प्रति:

foreach (string str in strings) 
{ 
    var copy = str; // this will do the job 
    actions.Add(new Action(() => { Trace.WriteLine(copy); })); 
} 
+0

गाह, आप जीतते हैं। मुझे पता था कि इसे कैसे ठीक किया जाए, लेकिन मुझे कारण याद नहीं आया। बंद! मुझे बंद करने की ज़रूरत है! +1 :) – Joshua

+1

@ जोशुआ यह बहुत समय पहले नहीं था जब मैंने थोड़ा गहराई से सीखा :) :) यह आगे पढ़ने के लिए अच्छा हो सकता है http://stackoverflow.com/questions/9412672/lambda-expressions-with -मल्टीथ्रेडिंग-इन-सी-तेज –

+0

दिलचस्प, मुझे कभी एहसास नहीं हुआ। धन्यवाद। – demoncodemonkey

3

यह एक बहुत है जटिल स्थिति संक्षिप्त उत्तर बंद करने के लिए इसे असाइन करने से पहले स्थानीय चर की एक प्रतिलिपि बनाने के लिए है:

string copy = str; 
actions.Add(new Action(() => { Trace.WriteLine(copy); })); 

Check out this article on closures अधिक जानकारी के लिए।

3

यह व्यवहार Closures द्वारा सशर्त है।

चर है कि आपके लैम्ब्डा में मौजूद है एक संदर्भ और नहीं मूल्य प्रति है। इसका मतलब है कि str द्वारा अनुमानित नवीनतम मूल्य को इंगित करें, जो आपके मामले में "घी" है। यही कारण है कि प्रत्येक कॉल के लिए यह उसी मेमोरी लोकेशन पर जाता है और स्वाभाविक रूप से वही मान देता है।

आप कोड है, बशर्ते जवाब में की तरह लिखते हैं, आप एक नई मूल्य हर बार पुनर्जीवित करने के लिए एक C# संकलक मजबूर है, इसलिए एक नई पता labmda को दे दिया जाएगा, ताकि हर लैम्ब्डा यह है होगा स्वयं चर।

वैसे, अगर मैं गलती नहीं कर रहा हूँ, C# टीम वादा इस गैर प्राकृतिकC# 5.0 में व्यवहार ठीक करने के लिए। तो भविष्य में अपडेट के लिए इस विषय पर अपने ब्लॉग की जांच करना बेहतर है।

+2

+1 अच्छा स्पष्टीकरण। यह उल्लेखनीय हो सकता है कि जावा इसे दूसरी तरफ करता है। यदि आप धागे को शुरू करने के लिए 'रननेबल' (आमतौर पर) से निपटते हैं, तो वेरिएबल * नए संदर्भ में * कॉपी * होते हैं। यही कारण है कि जावा आपको उन्हें 'अंतिम' बनाने के लिए मजबूर करता है। –

संबंधित मुद्दे