2012-01-13 8 views
5

मैं निम्न विधि है:क्यों सी # अज्ञात प्रतिनिधि कॉल के संदर्भ को संरक्षित नहीं करता है?

static Random rr = new Random(); 
static void DoAction(Action a) 
{ 
    ThreadPool.QueueUserWorkItem(par => 
    { 
     Thread.Sleep(rr.Next(200)); 
     a.Invoke(); 
    }); 
} 

अब मैं इस एक में पाश के लिए इस तरह कहते हैं:

for (int i = 0; i < 10; i++) 
{ 
    var x = i; 

    DoAction(() => 
    { 
     Console.WriteLine(i); // scenario 1 
     //Console.WriteLine(x); // scenario 2 
    }); 
} 
परिदृश्य 1 आउटपुट में

है: 10 10 10 10 ... 10
परिदृश्य 2 में उत्पादन होता है: 2 6 5 8 4 ... 0 (0 से 9 के यादृच्छिक क्रमपरिवर्तन)

आप इसे कैसे समझाते हैं? अज्ञात प्रतिनिधि कॉल के लिए क्या सी # को चर ("i) संरक्षित नहीं करना चाहिए?

+2

लेकिन संरक्षित ('कैप्चरिंग') * चर * * i' * बिल्कुल * क्या हो रहा है! क्या * नहीं हो रहा है, यद्यपि आप इसे चाहते हैं, * प्रतिनिधि की स्थापना के समय 'i' के ** मूल्य ** को संरक्षित कर रहा है *। – AakashM

+2

संयोग से, रीशेर्पर आपको इस कोड के साथ प्रस्तुत किए जाने पर [संशोधित बंद करने के लिए एक्सेस] (http://confluence.jetbrains.net/display/ReSharper/Access+to+modified+closure) के बारे में चेतावनी देगा; आपको वहां स्पष्टीकरण मिल सकता है। – AakashM

+0

http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-cononsidered-harmful.aspx –

उत्तर

10

समस्या यह है कि एक i चर और दस उदाहरण/x की प्रतियां हैं। प्रत्येक लैम्ब्डा को एकल चर i और x के उदाहरणों में से एक का संदर्भ मिलता है। प्रत्येक x केवल एक बार लिखा जाता है और इसलिए प्रत्येक लैम्ब्डा एक मान को देखता है जो संदर्भ के संदर्भ में लिखा गया था।

चर i जब तक यह तक पहुँचता है 10 lambdas से कोई चलाने जब तक लूप तो पूरा करता है वे सभी i के अंतिम मूल्य जो 10

मैं इस उदाहरण को खोजने के एक सा है, तो आप स्पष्ट है यह देखने के लिए लिखा है इसे

int i = 0; // Single i for every iteration of the loop 
while (i < 10) { 
    int x = i; // New x for every iteration of the loop 
    DoAction(() => { 
    Console.WriteLine(i); 
    Console.WriteLine(x); 
    }); 
    i++; 
}; 
+1

अधिक स्पष्ट रूप से, प्रत्येक 'x' सिर्फ लिखा नहीं है केवल एक बार, लेकिन यह एक अलग 'x' है क्योंकि यह हर बार शुरू होता है। लूप के जीवनकाल में केवल 10 'x' है और केवल एक 'i' है। –

1

मुझे लगता है कि आपको जावा या किसी ऑब्जेक्ट उन्मुख भाषा के साथ एक ही परिणाम मिल जाएगा (यकीन नहीं है लेकिन यहां यह तार्किक लगता है)।

i का दायरा पूरे लूप के लिए है और प्रत्येक घटना के लिए x का दायरा है।

Resharper आपको इस तरह की समस्या को शीर्ष स्थान देने में मदद करता है।

1

DoAction धागे को फैलाता है, और तुरंत लौटता है। जब तक धागा अपनी यादृच्छिक नींद से जागता है, तो लूप समाप्त हो जाएगा, और i का मान 10 तक बढ़ जाएगा। दूसरी तरफ x का मूल्य कॉल से पहले कब्जा कर लिया गया है , इसलिए आपको 0 से 9 से यादृच्छिक क्रम में सभी मान प्राप्त होंगे, इस पर निर्भर करता है कि प्रत्येक थ्रेड आपके यादृच्छिक संख्या जनरेटर के आधार पर कितना समय तक सो जाता है।

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